diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/config.mk a/config.mk
--- b/config.mk	1970-01-01 03:00:00.000000000 +0300
+++ a/config.mk	2021-09-16 09:19:40.891396586 +0300
@@ -0,0 +1,62 @@
+#
+# FreeType 2 configuration rules for UNIX platforms
+#
+
+
+# Copyright (C) 1996-2021 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+# We need these declarations here since unix-def.mk is a generated file.
+PLATFORM_DIR := $(TOP_DIR)/builds/unix
+PLATFORM     := unix
+
+have_mk := $(wildcard $(OBJ_DIR)/unix-def.mk)
+ifneq ($(have_mk),)
+  # We are building FreeType 2 not in the src tree.
+  include $(OBJ_DIR)/unix-def.mk
+  include $(OBJ_DIR)/unix-cc.mk
+else
+  include $(PLATFORM_DIR)/unix-def.mk
+  include $(PLATFORM_DIR)/unix-cc.mk
+endif
+
+ifdef BUILD_PROJECT
+
+  .PHONY: clean_project distclean_project
+
+  # Now include the main sub-makefile.  It contains all the rules used to
+  # build the library with the previous variables defined.
+  #
+  include $(TOP_DIR)/builds/$(PROJECT).mk
+
+
+  # The cleanup targets.
+  #
+  clean_project: clean_project_unix
+  distclean_project: distclean_project_unix
+
+
+  # This final rule is used to link all object files into a single library.
+  # It is part of the system-specific sub-Makefile because not all
+  # librarians accept a simple syntax like
+  #
+  #   librarian library_file {list of object files}
+  #
+    $(PROJECT_LIBRARY): $(OBJECTS_LIST)
+  ifdef CLEAN_LIBRARY
+	    -$(CLEAN_LIBRARY) $(NO_OUTPUT)
+  endif
+	    $(LINK_LIBRARY)
+
+  include $(TOP_DIR)/builds/unix/install.mk
+
+endif
+
+
+# EOF
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/configure a/configure
--- b/configure	2021-02-13 10:16:54.000000000 +0200
+++ a/configure	2021-09-16 09:15:05.050379727 +0300
@@ -13,6 +13,8 @@
 # Call the `configure' script located in `builds/unix'.
 #
 
+export LDFLAGS="$LDFLAGS -lm"
+
 rm -f config.mk builds/unix/unix-def.mk builds/unix/unix-cc.mk
 
 # respect GNUMAKE environment variable for backward compatibility
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/devel/ftoption.h a/devel/ftoption.h
--- b/devel/ftoption.h	2021-07-15 13:09:04.000000000 +0300
+++ a/devel/ftoption.h	2021-09-16 09:15:05.050379727 +0300
@@ -629,6 +629,16 @@
    */
 #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable     */
+  /* all additional infinality patches, which are configured via env       */
+  /* variables.                                                            */
+  /*                                                                       */
+  /*   This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to           */
+  /*   defined.                                                            */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_INFINALITY_PATCHSET
 
   /**************************************************************************
    *
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/include/freetype/config/ftoption.h a/include/freetype/config/ftoption.h
--- b/include/freetype/config/ftoption.h	2021-07-15 13:09:04.000000000 +0300
+++ a/include/freetype/config/ftoption.h	2021-09-16 09:15:05.051379735 +0300
@@ -112,18 +112,21 @@
 #define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
 
 
-  /**************************************************************************
-   *
-   * Uncomment the line below if you want to activate LCD rendering
-   * technology similar to ClearType in this build of the library.  This
-   * technology triples the resolution in the direction color subpixels.  To
-   * mitigate color fringes inherent to this technology, you also need to
-   * explicitly set up LCD filtering.
-   *
-   * When this macro is not defined, FreeType offers alternative LCD
-   * rendering technology that produces excellent output.
-   */
-/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+  /*************************************************************************/
+  /*                                                                       */
+  /* Uncomment the line below if you want to activate LCD rendering        */
+  /* technology similar to ClearType in this build of the library.  This   */
+  /* technology triples the resolution in the direction color subpixels.   */
+  /* To mitigate color fringes inherent to this technology, you also need  */
+  /* to explicitly set up LCD filtering.                                   */
+  /*                                                                       */
+  /* Note that this feature is covered by several Microsoft patents        */
+  /* and should not be activated in any default build of the library.      */
+  /* When this macro is not defined, FreeType offers alternative LCD       */
+  /* rendering technology that produces excellent output without LCD       */
+  /* filtering.                                                            */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 
 
   /**************************************************************************
@@ -631,6 +634,17 @@
    */
 #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable     */
+  /* all additional infinality patches, which are configured via env       */
+  /* variables.                                                            */
+  /*                                                                       */
+  /*   This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to           */
+  /*   defined.                                                            */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_INFINALITY_PATCHSET
+
 
   /**************************************************************************
    *
@@ -688,8 +702,8 @@
    * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx
    */
 /* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING  1         */
-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING  2
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING  ( 1 | 2 ) */
+/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING  1 */
+#define TT_CONFIG_OPTION_SUBPIXEL_HINTING  ( 1 | 2 )
 
 
   /**************************************************************************
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/include/freetype/internal/ftobjs.h a/include/freetype/internal/ftobjs.h
--- b/include/freetype/internal/ftobjs.h	2021-02-13 10:16:54.000000000 +0200
+++ a/include/freetype/internal/ftobjs.h	2021-09-16 09:15:05.051379735 +0300
@@ -278,12 +278,14 @@
 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 
   typedef void  (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap*      bitmap,
+                                            FT_Render_Mode  render_mode,
                                             FT_Byte*        weights );
 
 
   /* This is the default LCD filter, an in-place, 5-tap FIR filter. */
   FT_BASE( void )
   ft_lcd_filter_fir( FT_Bitmap*           bitmap,
+                     FT_Render_Mode       mode,
                      FT_LcdFiveTapFilter  weights );
 
 #endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
@@ -908,6 +910,7 @@
     FT_DebugHook_Func  debug_hooks[4];
 
 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    FT_Int                   lcd_extra;        /* number of extra pixels */
     FT_LcdFiveTapFilter      lcd_weights;      /* filter weights, if any */
     FT_Bitmap_LcdFilterFunc  lcd_filter_func;  /* filtering callback     */
 #else
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/autofit/aflatin.c a/src/autofit/aflatin.c
--- b/src/autofit/aflatin.c	2021-07-12 15:07:00.000000000 +0300
+++ a/src/autofit/aflatin.c	2021-09-16 09:15:05.051379735 +0300
@@ -22,7 +22,10 @@
 #include "afglobal.h"
 #include "aflatin.h"
 #include "aferrors.h"
-
+#include "strings.h"
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "../base/ftinf.h"
+#endif
 
   /**************************************************************************
    *
@@ -33,6 +36,10 @@
 #undef  FT_COMPONENT
 #define FT_COMPONENT  aflatin
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+FT_Pos infinality_cur_width = 0;
+#endif
+
 
   /* needed for computation of round vs. flat segments */
 #define FLAT_THRESHOLD( x )  ( x / 14 )
@@ -1174,7 +1181,10 @@
     FT_Pos        delta;
     AF_LatinAxis  axis;
     FT_UInt       nn;
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    FT_Bool adjust_heights         = FALSE;
+    if(ftinf) adjust_heights=ftinf->autohint_increase_glyph_heights;
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
 
     if ( dim == AF_DIMENSION_HORZ )
     {
@@ -1202,7 +1212,7 @@
     {
       AF_LatinAxis  Axis = &metrics->axis[AF_DIMENSION_VERT];
       AF_LatinBlue  blue = NULL;
-
+      int threshold = 40;
 
       for ( nn = 0; nn < Axis->blue_count; nn++ )
       {
@@ -1212,7 +1222,12 @@
           break;
         }
       }
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      if ( adjust_heights                                       &&
+           metrics->root.scaler.face->size->metrics.x_ppem < 15 &&
+           metrics->root.scaler.face->size->metrics.x_ppem > 5  )
+        threshold = 52;
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
       if ( blue )
       {
         FT_Pos   scaled;
@@ -1369,7 +1384,13 @@
 
         /* a blue zone is only active if it is less than 3/4 pixels tall */
         dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
+
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+        /* Do at low ppems ( ~< 200 ), in order to prevent fringes */
+        if ( dist <= 256 && dist >= -256 )
+#else
         if ( dist <= 48 && dist >= -48 )
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
         {
 #if 0
           FT_Pos  delta1;
@@ -1420,7 +1441,12 @@
             delta2 = -delta2;
 
           blue->ref.fit   = FT_PIX_ROUND( blue->ref.cur );
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+          /* Round to prevent fringes */
+          blue->shoot.fit = FT_PIX_ROUND( blue->ref.fit - delta2 );
+#else
           blue->shoot.fit = blue->ref.fit - delta2;
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
 
 #endif
 
@@ -2583,7 +2609,10 @@
               dist = edge->fpos - blue->shoot.org;
               if ( dist < 0 )
                 dist = -dist;
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+              /* round down to pixels */
+              /*dist = FT_MulFix( dist, scale ) & ~63;*/
+#endif
               dist = FT_MulFix( dist, scale );
               if ( dist < best_dist )
               {
@@ -2748,8 +2777,17 @@
     FT_Pos           dist     = width;
     FT_Int           sign     = 0;
     FT_Int           vertical = ( dim == AF_DIMENSION_VERT );
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    FT_Int           infinality_dist = 0;
+    FT_UInt          autohint_snap_stem_height = 0;
+    if( ftinf ) autohint_snap_stem_height=ftinf->autohint_snap_stem_height;
+    if ( autohint_snap_stem_height > 100 )
+        autohint_snap_stem_height = 100;
+    else if ( autohint_snap_stem_height < 0 )
+        autohint_snap_stem_height = 0;
 
-
+    if ( autohint_snap_stem_height == 0 )
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
     if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
          axis->extra_light                       )
       return width;
@@ -2759,9 +2797,76 @@
       dist = -width;
       sign = 1;
     }
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    /* Calculate snap value differently than standard freetype */
+    if ( autohint_snap_stem_height > 0                              &&
+         ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) )  ||
+           ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) )
+    {
+      infinality_dist = af_latin_snap_width( axis->widths,
+                                             axis->width_count, dist );
+
+      if ( metrics->root.scaler.face->size->metrics.x_ppem > 9 &&
+           axis->width_count > 0                               &&
+           abs( axis->widths[0].cur - infinality_dist ) < 32   &&
+           axis->widths[0].cur > 52                            )
+      {
+          const char *style_name=metrics->root.scaler.face->style_name;
+          if ( style_name!=NULL &&
+               ( strstr( style_name, "Regular" )      ||
+                 strstr( style_name, "Book" )         ||
+                 strstr( style_name, "Medium" )       ||
+                 strcmp( style_name, "Italic" ) == 0  ||
+                 strcmp( style_name, "Oblique" ) == 0 )
+              )
+         {
+          /* regular weight */
+          if ( axis->widths[0].cur < 64 )
+            infinality_dist = 64;
+          else if ( axis->widths[0].cur  < 88 )
+            infinality_dist = 64;
+          else if ( axis->widths[0].cur  < 160 )
+            infinality_dist = 128;
+          else if ( axis->widths[0].cur  < 240 )
+            infinality_dist = 190;
+          else infinality_dist = ( infinality_dist ) & ~63;
+        }
+        else
+        {
+          /* bold gets a different threshold */
+          if ( axis->widths[0].cur < 64 )
+            infinality_dist = 64 ;
+          else if ( axis->widths[0].cur  < 108 )
+            infinality_dist = 64;
+          else if ( axis->widths[0].cur  < 160 )
+            infinality_dist = 128;
+          else if ( axis->widths[0].cur  < 222 )
+            infinality_dist = 190;
+          else if ( axis->widths[0].cur  < 288 )
+            infinality_dist = 254;
+          else infinality_dist = ( infinality_dist + 16 ) & ~63;
+        }
+
+      }
+      if ( infinality_dist < 52 )
+      {
+        if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 )
+        {
+          if ( infinality_dist < 32 )
+            infinality_dist = 32;
+        }
+        else
+          infinality_dist = 64;
+      }
+    }
+    else if ( autohint_snap_stem_height < 100                            &&
+              ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) )  ||
+                ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) )
+#else
 
     if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
          ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
     {
       /* smooth hinting process: very lightly quantize the stem width */
 
@@ -2853,6 +2958,9 @@
       }
     }
     else
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      if ( autohint_snap_stem_height < 100 )
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
     {
       /* strong hinting process: snap the stem width to integer pixels */
 
@@ -2860,7 +2968,10 @@
 
 
       dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      if ( autohint_snap_stem_height > 0 )
+        goto Done_Width;
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
       if ( vertical )
       {
         /* in the case of vertical hinting, always round */
@@ -2923,6 +3034,32 @@
     }
 
   Done_Width:
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    if ( axis->widths[0].cur > 42 )
+      /* weighted average */
+      dist = (dist * ( 100 - autohint_snap_stem_height )
+                + infinality_dist * autohint_snap_stem_height ) / 100;
+
+      {
+        int factor = 100;
+        if ( axis->standard_width < 100 )
+          factor = axis->standard_width;
+
+        if ( metrics->root.scaler.face->size->metrics.x_ppem >= 9  && dist < 52 )
+          dist += ( (52 - dist) * factor ) / 100;
+        if ( metrics->root.scaler.face->size->metrics.x_ppem < 9  && dist < 32 )
+          dist += ( (32 - dist) * factor ) / 100;
+
+        if ( axis->standard_width > 100                             &&
+             metrics->root.scaler.face->size->metrics.x_ppem >= 11  &&
+             dist < 64                                              )
+          dist = 64;
+        if ( axis->standard_width > 100                           &&
+             metrics->root.scaler.face->size->metrics.x_ppem >= 9 &&
+             dist < 52                                            )
+          dist = 52;
+      }
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
     if ( sign )
       dist = -dist;
 
@@ -2941,6 +3078,8 @@
     FT_Pos  dist, base_delta;
     FT_Pos  fitted_width;
 
+/* if fitted_width causes stem_edge->pos to land basically on top of an existing
+ * stem_edge->pos, then add or remove 64.  Need to figure out a way to do this */
 
     dist       = stem_edge->opos - base_edge->opos;
     base_delta = base_edge->pos - base_edge->opos;
@@ -3548,8 +3687,11 @@
     int       dim;
 
     AF_LatinAxis  axis;
-
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    FT_Int    emboldening_strength = 0;
+    FT_Bool   use_various_tweaks = FALSE;
+    if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
     error = af_glyph_hints_reload( hints, outline );
     if ( error )
       goto Exit;
@@ -3595,7 +3737,11 @@
     }
 
     af_glyph_hints_save( hints, outline );
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    {
+      infinality_cur_width = metrics->axis->widths[0].cur;
+    }
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
   Exit:
     return error;
   }
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/autofit/aflatin.h a/src/autofit/aflatin.h
--- b/src/autofit/aflatin.h	2021-02-13 10:16:54.000000000 +0200
+++ a/src/autofit/aflatin.h	2021-09-16 09:15:05.051379735 +0300
@@ -64,6 +64,9 @@
 
 #define AF_LATIN_MAX_WIDTHS  16
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    extern FT_Pos infinality_cur_width;
+#endif
 
 #define AF_LATIN_BLUE_ACTIVE      ( 1U << 0 ) /* zone height is <= 3/4px   */
 #define AF_LATIN_BLUE_TOP         ( 1U << 1 ) /* we have a top blue zone   */
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/autofit/afmodule.c a/src/autofit/afmodule.c
--- b/src/autofit/afmodule.c	2021-07-12 15:07:00.000000000 +0300
+++ a/src/autofit/afmodule.c	2021-09-16 09:15:05.051379735 +0300
@@ -21,6 +21,10 @@
 #include "afloader.h"
 #include "aferrors.h"
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "../base/ftinf.h"
+#endif
+
 #ifdef FT_DEBUG_AUTOFIT
 
 #ifndef FT_MAKE_OPTION_SINGLE_OBJECT
@@ -405,6 +409,9 @@
     module->fallback_style    = AF_STYLE_FALLBACK;
     module->default_script    = AF_SCRIPT_DEFAULT;
     module->no_stem_darkening = TRUE;
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    if(ftinf) module->no_stem_darkening = !ftinf->stem_darkening_autofit;
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
 
     module->darken_params[0]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
     module->darken_params[1]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftbase.c a/src/base/ftbase.c
--- b/src/base/ftbase.c	2021-02-13 10:16:54.000000000 +0200
+++ a/src/base/ftbase.c	2021-09-16 09:15:05.051379735 +0300
@@ -36,6 +36,9 @@
 #include "ftstream.c"
 #include "fttrigon.c"
 #include "ftutil.c"
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "ftinf.c"
+#endif
 
 
 /* END */
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf.c a/src/base/ftinf.c
--- b/src/base/ftinf.c	1970-01-01 03:00:00.000000000 +0300
+++ a/src/base/ftinf.c	2021-09-16 09:15:05.052379743 +0300
@@ -0,0 +1,363 @@
+#include <stdlib.h>
+#include "ftinf.h"
+#define true  1
+#define false 0
+
+#define on  1
+#define off 0
+#define end (-128)
+
+#define sw2pv 18  /* STEM_WIDTH_2_PPEM */
+#define maxp 100  /* MAX_PPEM */
+
+typedef signed char pv;         /* ppm and values type */
+/* the arrays start with existence flag + values */
+typedef struct sa_rules_s {
+    const char *name;
+    pv always_use_100[1+4+1];
+    pv brightness[1+2+1];
+    pv contrast[1+2+1];
+    pv edge_detection[1+4+1];
+    pv m[1+4+1];
+    pv bearing_correction[1+2+1];
+    pv spacing[1+5+1];
+    pv start[1+5+1];
+    pv stem_scaling[1+6+1];
+    pv stem_translating[1+2+1];
+    pv stem_translating_only[1+10+1];
+    pv stem_widths[1+4];        /* these end with maxp */
+    pv synthesize_stems[1+2+1];
+} sa_rules_t;
+
+#pragma GCC diagnostic ignored "-Wpedantic" /* C99 struct initializer tags are needed */
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+const ftinf_t *ftinf;
+/* final settings, updated from environment */
+ftinf_t _env;
+
+/* rules and hashing function */
+#include "ftinf_rh.c"
+
+/* rules selection */
+void ftinf_fill_stem_values( Stem_Data *stem_values,
+                             const char *family, int ppem, int use_known ){
+    /* set the defaults */
+    stem_values->bearing_correction = TRUE;
+    stem_values->brightness = 0.0;
+    stem_values->contrast = 0.0;
+    stem_values->edge_detection = FALSE;
+    stem_values->m = -1;
+    stem_values->stem_scaling = -1;
+    stem_values->stem_spacing = -1;
+    stem_values->stem_start = -1;
+    stem_values->stem_translating = 0;
+    stem_values->stem_translating_only = -1024;
+    stem_values->stem_width = -1;
+    stem_values->synth_stems = FALSE;
+    stem_values->use_100 = FALSE;
+    /* pick from known rules if requested and they exist for current family */
+    if( !use_known )
+        return;
+    else {
+        const sa_rules_t *r=ftinf_rules( family );
+        int i;
+        if( r==NULL ) return;
+        if( r->stem_widths[0]==on )
+            for( i=1; r->stem_widths[i]!=maxp; ++i )
+                if( ppem < r->stem_widths[i] ){
+                    stem_values->stem_width = i-1;
+                    break;
+                }
+
+        if( r->stem_scaling[0]==on )
+            for( i=1; r->stem_scaling[i]!=end; i+=2 )
+                if( ppem==r->stem_scaling[i] ){
+                    stem_values->stem_scaling = r->stem_scaling[i+1];
+                    break;
+                }
+
+        if( r->m[0]==on )
+            for( i=1; r->m[i]!=end; i+=2 )
+                if( ppem==r->m[i] ){
+                    stem_values->m = r->m[i+1];
+                    break;
+                }
+
+        if( r->stem_translating_only[0]==on )
+            for( i=1; r->stem_translating_only[i]!=end; i+=2 )
+                if( ppem==r->stem_translating_only[i] || r->stem_translating_only[i]==0 ){
+                    stem_values->stem_translating_only = r->stem_translating_only[i+1];
+                    break;
+                }
+
+        if( r->stem_translating[0]==on )
+            for( i=1; r->stem_translating[i]!=end; i+=2 )
+                if( ppem==r->stem_translating[i] || r->stem_translating[i]==0 ){
+                    stem_values->stem_translating = r->stem_translating[i+1];
+                    break;
+                }
+
+        if( r->always_use_100[0]==on )
+            for( i=1; r->always_use_100[i]!=end; i+=2 )
+                if( ppem>=r->always_use_100[i] && ppem<=r->always_use_100[i+1] ){
+                    stem_values->use_100 = TRUE;
+                    break;
+                }
+
+        if( r->synthesize_stems[0]==on )
+            for( i=1; r->synthesize_stems[i]!=end; i+=2 )
+                if( ppem>=r->synthesize_stems[i] && ppem<=r->synthesize_stems[i+1] ){
+                    stem_values->synth_stems = TRUE;
+                    break;
+                }
+
+        if( r->edge_detection[0]==on )
+            for( i=1; r->edge_detection[i]!=end; i+=2 )
+                if( ppem>=r->edge_detection[i] && ppem<=r->edge_detection[i+1] ){
+                    stem_values->edge_detection = TRUE;
+                    break;
+                }
+
+        if( r->bearing_correction[0]==on )
+            for( i=1; r->bearing_correction[i]!=end; i+=2 )
+                if( ppem>=r->bearing_correction[i] && ppem<=r->bearing_correction[i+1] ){
+                    stem_values->bearing_correction = FALSE;
+                    break;
+                }
+
+#if(0)
+        if( r->brightness[0]==on )
+            for( i=1; r->brightness[i]!=end; i+=2 )
+                if( ppem==r->brightness[i]||r->brightness[i]==0 ){
+                    stem_values->brightness=r->brightness[i+1]*(1.0f/300.0f);
+                    break;
+                }
+
+        if( r->contrast[0]==on )
+            for( i=1; r->contrast[i]!=end; i+=2 )
+                if( ppem==r->contrast[i]||r->contrast[i]==0 ){
+                    stem_values->contrast=r->contrast[i+1]*(1.0f/300.0f);
+                    break;
+                }
+        if( r->spacing[0]==on ){
+            /* not used by original code */
+        }
+        if( r->start[0]==on ){
+            /* not used by original code */
+        }
+#endif
+    }
+    return;
+}
+
+void ftinf_get_bc( const char *family, int ppem, float *brightness, float *contrast ){
+    const sa_rules_t *r=ftinf_rules( family );
+    *brightness=0;
+    *contrast=0;
+    if( r ){
+        int i;
+        if( r->brightness[0]==on )
+            for( i=1; r->brightness[i]!=end; i+=2 )
+                if( ppem==r->brightness[i]||r->brightness[i]==0 ){
+                    *brightness=r->brightness[i+1]*(1.0f/300.0f);
+                    break;
+                }
+
+        if( r->contrast[0]==on )
+            for( i=1; r->contrast[i]!=end; i+=2 )
+                if( ppem==r->contrast[i]||r->contrast[i]==0 ){
+                    *contrast=r->contrast[i+1]*(1.0f/300.0f);
+                    break;
+                }
+    }
+    return;
+}
+
+static int
+bool_val( const char *s ){
+    if ( s != NULL )
+        return strcasecmp(s, "true") == 0
+            || strcasecmp(s, "1") == 0
+            || strcasecmp(s, "on") == 0
+            || strcasecmp(s, "yes") ==0;
+    else
+        return 0;
+}
+
+static int
+int_val( const char *s, int min, int max ){
+    int val;
+    sscanf ( s, "%d", &val );
+    if ( val > max )
+        val = max;
+    else if ( val < min )
+        val = min;
+    return val;
+}
+
+/* settings and hashing function */
+#include "ftinf_sh.c"
+
+/*
+  Get active Infinality settings
+ */
+void ftinf_env(){
+    const char *s;
+    ftinf=ftinf_settings( getenv( "INFINALITY_FT" ) );
+
+    if( ftinf==NULL ){
+        ftinf=ftinf_settings( "ultimate3" );
+        /* this should always succeed */
+#if(0)
+        if( ftinf==NULL ){
+            /* put an error here */
+            exit(-1);
+        }
+#endif
+    }
+    _env=ftinf[0];      /* copy as defaults */
+
+    /* check if custom environment values are set and update with them */
+    s=getenv( "INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS" );
+    if( s ) _env.autohint_increase_glyph_heights=bool_val( s );
+    s=getenv( "INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT" );
+    if( s ) _env.autohint_snap_stem_height=int_val( s, 0, 100 );
+    s=getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" );
+    if( s ) _env.use_various_tweaks=bool_val( s );
+    s=getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" );
+    if( s ) _env.use_known_settings_on_selected_fonts=bool_val(s);
+#if(0)                          /* not used (naming error also) */
+    s=getenv( "INFINALITY_FT_AUTOHINT_MINIMUM_STEM_WIDTH" );
+    if( s ) _env.autohint_minimum_stem_height=int_val( s, 0, 100 );
+#endif
+    s=getenv( "INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE" );
+    if( s ) sscanf( s, "%d", &_env.stem_snapping_sliding_scale );
+    s=getenv( "INFINALITY_FT_STEM_ALIGNMENT_STRENGTH" );
+    if( s ) sscanf( s, "%d", &_env.stem_alignment_strength );
+    s=getenv( "INFINALITY_FT_STEM_DARKENING_AUTOFIT" );
+    if( s ) _env.stem_darkening_autofit=bool_val( s );
+    s=getenv( "INFINALITY_FT_STEM_DARKENING_CFF" );
+    if( s ) _env.stem_darkening_cff=bool_val( s );
+    s=getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" );
+    if( s ) sscanf( s, "%d", &_env.stem_fitting_strength );
+    s=getenv( "INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH" );
+    if( s ) _env.chromeos_style_sharpening_strength=int_val( s, 0, 100 );
+    s=getenv( "INFINALITY_FT_BRIGHTNESS" );
+    if( s ) sscanf( s, "%d", &_env.brightness );
+    s=getenv( "INFINALITY_FT_CONTRAST" );
+    if( s ) sscanf( s, "%d", &_env.contrast );
+    s=getenv( "INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH" );
+    if( s ) _env.windows_style_sharpening_strength=int_val( s, 0, 100 );
+    s=getenv( "INFINALITY_FT_GAMMA_CORRECTION" );
+    if( s ){
+        float *f=_env.gamma_correction;
+        sscanf ( s, "%f %f", &f[0], &f[1] );
+        if( f[1] < 1.0f ) f[1]=1.0f;
+    }
+    s=getenv( "INFINALITY_FT_FRINGE_FILTER_STRENGTH" );
+    if( s ) sscanf( s, "%d", &_env.fringe_filter_strength );
+    s=getenv( "INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH" );
+    if( s ) sscanf( s, "%d", &_env.grayscale_filter_strength );
+    s=getenv( "INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH" );
+    if( s ) sscanf( s, "%d", &_env.autohint_horizontal_stem_darken_strength );
+    s=getenv( "INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH" );
+    if( s ) sscanf( s, "%d", &_env.autohint_vertical_stem_darken_strength );
+    s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE" );
+    if( s ) sscanf( s, "%d", &_env.global_embolden_x_value );
+    s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE" );
+    if( s ) sscanf( s, "%d", &_env.global_embolden_y_value );
+    s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE" );
+    if( s ) sscanf( s, "%d", &_env.bold_embolden_x_value );
+    s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE" );
+    if( s ) sscanf( s, "%d", &_env.bold_embolden_y_value );
+    s=getenv( "INFINALITY_FT_FILTER_PARAMS" );
+    if( s ) {
+        int *f=_env.filter_params;
+        if( sscanf( s, "%d %d %d %d %d", f+1, f+2, f+3, f+4, f+5 )==5 )
+            f[0]=on;
+        else
+            f[0]=off;           /* FIXME: put a warning? */
+    }
+    /* do the range verifications as in original code */
+    if ( _env.stem_snapping_sliding_scale > maxp )
+        _env.stem_snapping_sliding_scale = 0;
+    else if ( _env.stem_snapping_sliding_scale < 0 )
+        _env.stem_snapping_sliding_scale = 0;
+    if (_env.stem_snapping_sliding_scale < 11 &&
+        _env.stem_snapping_sliding_scale > 0  )
+        _env.stem_snapping_sliding_scale = 11;
+
+    if ( _env.stem_alignment_strength > 100 )
+        _env.stem_alignment_strength = 100;
+    else if ( _env.stem_alignment_strength < 0 )
+        _env.stem_alignment_strength = 0;
+
+    if ( _env.stem_fitting_strength > 100 )
+        _env.stem_fitting_strength = 100;
+    else if ( _env.stem_fitting_strength < 0 )
+        _env.stem_fitting_strength = 0;
+
+    if ( _env.chromeos_style_sharpening_strength > 100 )
+        _env.chromeos_style_sharpening_strength = 100;
+    else if ( _env.chromeos_style_sharpening_strength < 0 )
+        _env.chromeos_style_sharpening_strength = 0;
+
+    if ( _env.brightness > 100 )
+        _env.brightness = 100;
+    else if ( _env.brightness < -100 )
+        _env.brightness = 0;
+
+    if ( _env.contrast > 100 )
+        _env.contrast = 100;
+    else if ( _env.contrast < -100 )
+        _env.contrast = 0;
+
+    if ( _env.windows_style_sharpening_strength > 100 )
+        _env.windows_style_sharpening_strength = 100;
+    else if ( _env.windows_style_sharpening_strength < 0 )
+        _env.windows_style_sharpening_strength = 0;
+
+    if ( _env.fringe_filter_strength > 100 )
+        _env.fringe_filter_strength = 100;
+    else if ( _env.fringe_filter_strength < 0 )
+        _env.fringe_filter_strength = 0;
+
+    if ( _env.grayscale_filter_strength > 100 )
+        _env.grayscale_filter_strength = 100;
+    else if ( _env.grayscale_filter_strength < 0 )
+        _env.grayscale_filter_strength = 0;
+
+    if ( _env.autohint_horizontal_stem_darken_strength > 100 )
+        _env.autohint_horizontal_stem_darken_strength = 100;
+    else if ( _env.autohint_horizontal_stem_darken_strength < 0 )
+        _env.autohint_horizontal_stem_darken_strength = 0;
+
+    if ( _env.autohint_vertical_stem_darken_strength > 100 )
+        _env.autohint_vertical_stem_darken_strength = 100;
+    else if ( _env.autohint_horizontal_stem_darken_strength < 0 )
+        _env.autohint_vertical_stem_darken_strength = 0;
+
+    if ( _env.global_embolden_x_value > 128 )
+        _env.global_embolden_x_value = 128;
+    else if ( _env.global_embolden_x_value < -128 )
+        _env.global_embolden_x_value = -128;
+
+    if ( _env.global_embolden_y_value > 128 )
+        _env.global_embolden_y_value = 128;
+    else if ( _env.global_embolden_y_value < -128 )
+          _env.global_embolden_y_value = -128;
+
+    if ( _env.bold_embolden_x_value > 128 )
+        _env.bold_embolden_x_value = 128;
+    else if (_env.bold_embolden_x_value < -128 )
+        _env.bold_embolden_x_value = -128;
+
+    if ( _env.bold_embolden_y_value > 128 )
+        _env.bold_embolden_y_value = 128;
+    else if ( _env.bold_embolden_y_value < -128 )
+        _env.bold_embolden_y_value = -128;
+
+    /* point to the combined and checked settings */
+    ftinf=&_env;
+}
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf.h a/src/base/ftinf.h
--- b/src/base/ftinf.h	1970-01-01 03:00:00.000000000 +0300
+++ a/src/base/ftinf.h	2021-09-16 09:15:05.052379743 +0300
@@ -0,0 +1,66 @@
+#ifndef _FTINF_H_
+#define _FTINF_H_
+/*
+    Stem snapping rules
+    (base freetype typedefs assumed already included)
+ */
+typedef struct
+{
+    FT_Int       stem_width;
+    FT_Int       stem_spacing;
+    FT_Int       stem_start;
+    FT_Int       stem_scaling;
+    FT_Int       stem_translating_only;
+    FT_Int       stem_translating;
+    float        brightness;
+    float        contrast;
+    FT_Bool      use_100;
+    FT_Bool      synth_stems;
+    FT_Bool      edge_detection;
+    FT_Bool      bearing_correction;
+    FT_Int       m;
+} Stem_Data;
+
+/*
+  Infinality settings
+ */
+typedef struct ftinf_s {
+    const char *name;
+    int autohint_horizontal_stem_darken_strength;
+    int autohint_snap_stem_height;
+    int autohint_increase_glyph_heights;
+    int autohint_vertical_stem_darken_strength;
+    int bold_embolden_x_value;
+    int bold_embolden_y_value;
+    int brightness;
+    int chromeos_style_sharpening_strength;
+    int contrast;
+    int filter_params[6];       /* 1st one used as existence flag */
+    int fringe_filter_strength;
+    float gamma_correction[2];
+    int global_embolden_x_value;
+    int global_embolden_y_value;
+    int grayscale_filter_strength;
+    int stem_alignment_strength;
+    int stem_darkening_autofit;
+    int stem_darkening_cff;
+    int stem_fitting_strength;
+    int stem_snapping_sliding_scale;
+    int use_known_settings_on_selected_fonts;
+    int use_various_tweaks;
+    int windows_style_sharpening_strength;
+} ftinf_t;
+
+extern FT_Pos infinality_cur_width; /* defined in aflatin.c */
+
+extern const ftinf_t *ftinf;    /* active settings */
+
+extern void ftinf_fill_stem_values( Stem_Data *stem_values,
+                                    const char *family, int ppem, int use_known );
+extern void ftinf_get_bc( const char *family, int ppem,
+                          float *brightness, float *contrast );
+
+/* get values from environment (FIXME: maybe update with using user files) */
+extern void ftinf_env();
+
+#endif
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_rh.c a/src/base/ftinf_rh.c
--- b/src/base/ftinf_rh.c	1970-01-01 03:00:00.000000000 +0300
+++ a/src/base/ftinf_rh.c	2021-09-16 09:15:05.052379743 +0300
@@ -0,0 +1,626 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf --output-file=ftinf_rh.c ftinf_rh.gperf  */
+/* Computed positions: -k'1,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 9 "ftinf_rh.gperf"
+
+#include <ctype.h>
+static const struct sa_rules_s* _rules_get( const char*str, unsigned len );
+/* maximum key range = 82, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+_rules_hash (register const char *str, register unsigned int len)
+{
+  static const unsigned char asso_values[] =
+    {
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85,  0, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85,  5, 45,  5,
+      35, 25, 35, 35, 50, 45, 85, 85,  0, 25,
+      40,  5,  0, 85, 50, 20, 20,  0, 10, 10,
+      85, 10, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85
+    };
+  return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
+}
+
+#ifdef __GNUC__
+__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const struct sa_rules_s *
+_rules_get (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 58,
+      MIN_WORD_LENGTH = 3,
+      MAX_WORD_LENGTH = 24,
+      MIN_HASH_VALUE = 3,
+      MAX_HASH_VALUE = 84
+    };
+
+  static const struct sa_rules_s wordlist[] =
+    {
+#line 15 "ftinf_rh.gperf"
+{   .name="---",
+    .synthesize_stems={on, 13, 13, end}
+},
+#line 253 "ftinf_rh.gperf"
+{   .name="ubuntu",
+    .always_use_100={on, 12, 13, 15, 15, end}
+},
+#line 31 "ftinf_rh.gperf"
+{   .name="arial",
+    .always_use_100={on, 0, maxp, end},
+    .edge_detection={on, 11, 11, 13, 13, end},
+    .spacing={on, 10, 11, 23, 25, 30, end},
+    .start={on, 11, 18, 23, 30, 30, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end}
+},
+#line 87 "ftinf_rh.gperf"
+{   .name="corbel",
+    .stem_translating_only={on, 10, 16, end},
+    .stem_widths={on, 10, 21, maxp}
+},
+#line 71 "ftinf_rh.gperf"
+{   .name="canwell",
+    .stem_scaling={on, 13, 0, end}
+},
+#line 216 "ftinf_rh.gperf"
+{   .name="pragmata",
+    .always_use_100={on, 0, maxp, end}
+},
+#line 67 "ftinf_rh.gperf"
+{   .name="cantarell",
+    .stem_translating_only={on, 11, 0, 12, 0, end},
+    .stem_widths={on, 10, 22, maxp,}
+},
+#line 39 "ftinf_rh.gperf"
+{   .name="arimo",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}
+},
+#line 207 "ftinf_rh.gperf"
+{   .name="optima",
+    .brightness={on, 0, -20, end},
+    .contrast={on, 0, 25, end},
+    .stem_scaling={on, 17, 1, end},
+    .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end}
+},
+#line 63 "ftinf_rh.gperf"
+{   .name="candara",
+    .stem_scaling={on, 14, 1, 17, 1, end},
+    .stem_translating_only={on, 10, 16, end}
+},
+#line 77 "ftinf_rh.gperf"
+{   .name="comfortaa",
+    .stem_widths={on, 10, 19, 22, maxp},
+    .stem_scaling={on, 11, 0, end}
+},
+#line 161 "ftinf_rh.gperf"
+{   .name="liberation mono",
+    .always_use_100={on, 0, maxp, end}
+},
+#line 18 "ftinf_rh.gperf"
+{   .name="andale mono",
+    .always_use_100={on, 0, maxp, end},
+    .stem_scaling={on, 11, 1, end},
+    .stem_widths={on, 10, 21, maxp,}
+},
+#line 256 "ftinf_rh.gperf"
+{   .name="verdana",
+    .always_use_100={on, 0, 14, 16, maxp, end},
+    .stem_scaling={on, 12, 1, 15, 1, end},
+    .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end}
+},
+#line 74 "ftinf_rh.gperf"
+{   .name="century gothic",
+    .stem_widths={on, 10, 22, maxp,}
+},
+#line 91 "ftinf_rh.gperf"
+{   .name="courier new",
+    .always_use_100={on, 12, 12, end},
+    .edge_detection={on, 10, 12, end},
+    .m={on, 13, 1, 14, 1, end}
+},
+#line 23 "ftinf_rh.gperf"
+{   .name="arial narrow",
+    .stem_widths={on, 10, 21, maxp,}
+},
+#line 185 "ftinf_rh.gperf"
+{   .name="luxi sans",
+    .always_use_100={on, 13, 13, end},
+    .stem_widths={on, 10, 17, sw2pv, maxp,}
+},
+#line 225 "ftinf_rh.gperf"
+{   .name="samba",
+    .stem_scaling={on, 11, 0, end}
+},
+#line 233 "ftinf_rh.gperf"
+{   .name="tahoma",
+    .always_use_100={on, 11, 11, 14, maxp, end},
+    .edge_detection={on, 11, 11, end},
+    .spacing={on, 10, 12, 18, 18, 30, end},
+    .start={on, 14, 17, 30, 100, 100, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end},
+},
+#line 164 "ftinf_rh.gperf"
+{   .name="liberation sans narrow",
+    .stem_widths={on,10, 22, maxp,}
+},
+#line 81 "ftinf_rh.gperf"
+{   .name="consolas",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating_only={on, 8, 32, 9, 32, end},
+    .stem_widths={on, 10, 20, maxp,},
+    .stem_scaling={on, 11, 1, end}
+},
+#line 203 "ftinf_rh.gperf"
+{   .name="open sans",
+    .stem_translating_only={on, 10, 16, 9, 16, end},
+    .stem_widths={on, 10, 20, maxp,}
+},
+#line 167 "ftinf_rh.gperf"
+{   .name="liberation sans",
+    .edge_detection={on, 11, 11, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end},
+    .stem_widths={on,10, 19, maxp,}
+},
+#line 193 "ftinf_rh.gperf"
+{   .name="monaco",
+    .always_use_100={on, 0, maxp, end}
+},
+#line 101 "ftinf_rh.gperf"
+{   .name="cousine",
+    .always_use_100={on, 0, maxp, end}
+},
+#line 176 "ftinf_rh.gperf"
+{   .name="lucida grande",
+    .stem_scaling={on, 13, 1, end},
+    .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
+    .stem_widths={on, 10, 16, sw2pv, maxp},
+},
+#line 173 "ftinf_rh.gperf"
+{   .name="lucida console",
+    .always_use_100={on, 0, maxp, end}
+},
+#line 196 "ftinf_rh.gperf"
+{   .name="myriad pro",
+    .stem_scaling={on, 14, 1, 17, 1, end},
+    .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end}
+},
+#line 26 "ftinf_rh.gperf"
+{   .name="arial unicode ms",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
+},
+#line 213 "ftinf_rh.gperf"
+{   .name="palatino linotype",
+    .edge_detection={on, 0, 100, end}
+},
+#line 181 "ftinf_rh.gperf"
+{   .name="lucida sans unicode",
+    .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
+    .stem_widths={on,10, 16, sw2pv, maxp,}
+},
+#line 140 "ftinf_rh.gperf"
+{   .name="futura",
+    .stem_widths={on, 10, 14, sw2pv, maxp,}
+},
+#line 147 "ftinf_rh.gperf"
+{   .name="georgia",
+    .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end}
+},
+#line 125 "ftinf_rh.gperf"
+{   .name="freemono",
+    .always_use_100={on, 0, maxp, end}
+},
+#line 200 "ftinf_rh.gperf"
+{   .name="nina",
+    .stem_scaling={on, 11, 0, 12, 0, 13, 0, end}
+},
+#line 121 "ftinf_rh.gperf"
+{   .name="essential pragmatapro",
+    .always_use_100={on, 0, maxp, end},
+    .m={on, 13, 0, 14, 0, end}
+},
+#line 247 "ftinf_rh.gperf"
+{   .name="trebuchet ms",
+    .always_use_100={on, 13, 13, end},
+    .stem_scaling={on, 13, 0, 17, 0, 20, 1, end},
+    .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end},
+    .stem_widths={on, 10, 17, sw2pv, maxp,}
+},
+#line 114 "ftinf_rh.gperf"
+{   .name="droid sans mono",
+    .m={on, 12, 0, end}
+},
+#line 104 "ftinf_rh.gperf"
+{   .name="dejavu sans mono",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end}
+},
+#line 57 "ftinf_rh.gperf"
+{   .name="calibri",
+    .always_use_100={on, 23, maxp, end},
+    .stem_scaling={on, 15, 1, 17, 1, 18, 1, end},
+    .stem_translating_only={on, 10, 16, 15, 0, end},
+    .stem_widths={on, 1, 10, 19, maxp,}
+},
+#line 156 "ftinf_rh.gperf"
+{   .name="inconsolata",
+    .stem_scaling={on, 12, 1, 15, 1, end},
+    .stem_translating_only={on, 10, 24, 9, 32, end},
+    .stem_widths={on, 10, 23, maxp,},
+},
+#line 96 "ftinf_rh.gperf"
+{   .name="courier",
+    .always_use_100={on, 0, maxp, end},
+    .m={on, 13, 1, 14, 1, end},
+    .stem_translating_only={on, 13, 16, 15, 0, end}
+},
+#line 128 "ftinf_rh.gperf"
+{   .name="freesans",
+    .always_use_100={on, 0, maxp, end},
+    .edge_detection={on, 11, 11, 13, 13, end},
+    .spacing={on, 10, 12, 18, 18, 30, end},
+    .start={on, 10, 18, 18, 25, 30, end},
+    .stem_scaling={on, 16, 0, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 16, 9, 8, end}
+},
+#line 150 "ftinf_rh.gperf"
+{   .name="gill sans",
+    .stem_widths={on, 10, 17, sw2pv, maxp,}
+},
+#line 117 "ftinf_rh.gperf"
+{   .name="droid sans",
+    .always_use_100={on, 12, 12, 15, 15, end},
+    .stem_translating_only={on, 8, 16, 9, 16, end}
+},
+#line 108 "ftinf_rh.gperf"
+{   .name="dejavu sans",
+    .always_use_100={on, 10, 14, 16, 17, end},
+    .m={on, 12, 0, end},
+    .stem_scaling={on, 12, 1, end},
+    .stem_translating_only={on, 8, 16, 15, -20, end}
+},
+#line 219 "ftinf_rh.gperf"
+{   .name="raleway",
+    .stem_scaling={on, 15, 0, end}
+},
+#line 153 "ftinf_rh.gperf"
+{   .name="helvetica cy",
+    .stem_widths={on, 10, 23, maxp,}
+},
+#line 228 "ftinf_rh.gperf"
+{   .name="segoe ui",
+    .always_use_100={on, 11, 12, 14, 14, end},
+    .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end},
+    .stem_widths={on, 10, 23, maxp,}
+},
+#line 48 "ftinf_rh.gperf"
+{   .name="bitstream vera sans mono",
+    .always_use_100={on, 0, maxp, end}
+},
+#line 241 "ftinf_rh.gperf"
+{   .name="times new roman",
+    .always_use_100={on, 14, 14, 16, 16, end},
+    .bearing_correction={0, 100, end},
+    .stem_scaling={on, 17, 1, end},
+    .stem_translating_only={on, 17, 8, end}
+},
+#line 222 "ftinf_rh.gperf"
+{   .name="rokkitt",
+    .stem_widths={on, 10, 21, maxp,}
+},
+#line 143 "ftinf_rh.gperf"
+{   .name="garamond",
+    .brightness={on, 0, -20, end},
+    .contrast={on, 0, 25, end}
+},
+#line 137 "ftinf_rh.gperf"
+{   .name="freeserif",
+    .stem_scaling={on, 13, 1, 17, 1, end}
+},
+#line 189 "ftinf_rh.gperf"
+{   .name="microsoft sans serif",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
+},
+#line 44 "ftinf_rh.gperf"
+{   .name="baskerville",
+    .brightness={on, 0, -20, end},
+    .contrast={on, 0, 25, end}
+},
+#line 51 "ftinf_rh.gperf"
+{   .name="bitstream vera sans",
+    .always_use_100={on, 10, 14, 16, 17, end},
+    .m={on, 12, 0, end},
+    .stem_scaling={on ,12, 1, end},
+    .stem_translating_only={on, 8, 16, end}
+}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = _rules_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
+        {
+          register const struct sa_rules_s *resword;
+
+          switch (key - 3)
+            {
+              case 0:
+                resword = &wordlist[0];
+                goto compare;
+              case 3:
+                resword = &wordlist[1];
+                goto compare;
+              case 7:
+                resword = &wordlist[2];
+                goto compare;
+              case 8:
+                resword = &wordlist[3];
+                goto compare;
+              case 9:
+                resword = &wordlist[4];
+                goto compare;
+              case 10:
+                resword = &wordlist[5];
+                goto compare;
+              case 11:
+                resword = &wordlist[6];
+                goto compare;
+              case 12:
+                resword = &wordlist[7];
+                goto compare;
+              case 13:
+                resword = &wordlist[8];
+                goto compare;
+              case 14:
+                resword = &wordlist[9];
+                goto compare;
+              case 16:
+                resword = &wordlist[10];
+                goto compare;
+              case 17:
+                resword = &wordlist[11];
+                goto compare;
+              case 18:
+                resword = &wordlist[12];
+                goto compare;
+              case 19:
+                resword = &wordlist[13];
+                goto compare;
+              case 21:
+                resword = &wordlist[14];
+                goto compare;
+              case 23:
+                resword = &wordlist[15];
+                goto compare;
+              case 24:
+                resword = &wordlist[16];
+                goto compare;
+              case 26:
+                resword = &wordlist[17];
+                goto compare;
+              case 27:
+                resword = &wordlist[18];
+                goto compare;
+              case 28:
+                resword = &wordlist[19];
+                goto compare;
+              case 29:
+                resword = &wordlist[20];
+                goto compare;
+              case 30:
+                resword = &wordlist[21];
+                goto compare;
+              case 31:
+                resword = &wordlist[22];
+                goto compare;
+              case 32:
+                resword = &wordlist[23];
+                goto compare;
+              case 33:
+                resword = &wordlist[24];
+                goto compare;
+              case 34:
+                resword = &wordlist[25];
+                goto compare;
+              case 35:
+                resword = &wordlist[26];
+                goto compare;
+              case 36:
+                resword = &wordlist[27];
+                goto compare;
+              case 37:
+                resword = &wordlist[28];
+                goto compare;
+              case 38:
+                resword = &wordlist[29];
+                goto compare;
+              case 39:
+                resword = &wordlist[30];
+                goto compare;
+              case 41:
+                resword = &wordlist[31];
+                goto compare;
+              case 43:
+                resword = &wordlist[32];
+                goto compare;
+              case 44:
+                resword = &wordlist[33];
+                goto compare;
+              case 45:
+                resword = &wordlist[34];
+                goto compare;
+              case 46:
+                resword = &wordlist[35];
+                goto compare;
+              case 48:
+                resword = &wordlist[36];
+                goto compare;
+              case 49:
+                resword = &wordlist[37];
+                goto compare;
+              case 52:
+                resword = &wordlist[38];
+                goto compare;
+              case 53:
+                resword = &wordlist[39];
+                goto compare;
+              case 54:
+                resword = &wordlist[40];
+                goto compare;
+              case 58:
+                resword = &wordlist[41];
+                goto compare;
+              case 59:
+                resword = &wordlist[42];
+                goto compare;
+              case 60:
+                resword = &wordlist[43];
+                goto compare;
+              case 61:
+                resword = &wordlist[44];
+                goto compare;
+              case 62:
+                resword = &wordlist[45];
+                goto compare;
+              case 63:
+                resword = &wordlist[46];
+                goto compare;
+              case 64:
+                resword = &wordlist[47];
+                goto compare;
+              case 69:
+                resword = &wordlist[48];
+                goto compare;
+              case 70:
+                resword = &wordlist[49];
+                goto compare;
+              case 71:
+                resword = &wordlist[50];
+                goto compare;
+              case 72:
+                resword = &wordlist[51];
+                goto compare;
+              case 74:
+                resword = &wordlist[52];
+                goto compare;
+              case 75:
+                resword = &wordlist[53];
+                goto compare;
+              case 76:
+                resword = &wordlist[54];
+                goto compare;
+              case 77:
+                resword = &wordlist[55];
+                goto compare;
+              case 78:
+                resword = &wordlist[56];
+                goto compare;
+              case 81:
+                resword = &wordlist[57];
+                goto compare;
+            }
+          return 0;
+        compare:
+          {
+            register const char *s = resword->name;
+
+            if (*str == *s && !strcmp (str + 1, s + 1))
+              return resword;
+          }
+        }
+    }
+  return 0;
+}
+#line 261 "ftinf_rh.gperf"
+
+
+static const sa_rules_t*
+ftinf_rules( const char *name ){
+    if( name ){
+        enum {
+            max_wlen=31
+        };
+        char buf[max_wlen+1];
+        int len=strlen( name );
+        if( len <= max_wlen ){
+            int i;
+            for( i=0; i<len; ++i )
+                buf[i]=tolower( name[i] );
+            buf[len]='\0';
+            return _rules_get( buf, len );
+        }
+    }
+    return NULL;
+}
+/*
+   gperf --output-file=ftinf_rh.c ftinf_rh.gperf
+*/
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_rh.gperf a/src/base/ftinf_rh.gperf
--- b/src/base/ftinf_rh.gperf	1970-01-01 03:00:00.000000000 +0300
+++ a/src/base/ftinf_rh.gperf	2021-09-16 09:15:05.052379743 +0300
@@ -0,0 +1,283 @@
+%struct-type
+%define slot-name name
+%enum
+%switch=1
+%readonly-tables
+%omit-struct-type
+%define lookup-function-name  _rules_get
+%define hash-function-name _rules_hash
+%{
+#include <ctype.h>
+static const struct sa_rules_s* _rules_get( const char*str, unsigned len );
+%}
+struct sa_rules_s;
+%%
+{   .name="---",
+    .synthesize_stems={on, 13, 13, end}
+},
+{   .name="andale mono",
+    .always_use_100={on, 0, maxp, end},
+    .stem_scaling={on, 11, 1, end},
+    .stem_widths={on, 10, 21, maxp,}
+},
+{   .name="arial narrow",
+    .stem_widths={on, 10, 21, maxp,}
+},
+{   .name="arial unicode ms",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
+},
+{   .name="arial",
+    .always_use_100={on, 0, maxp, end},
+    .edge_detection={on, 11, 11, 13, 13, end},
+    .spacing={on, 10, 11, 23, 25, 30, end},
+    .start={on, 11, 18, 23, 30, 30, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end}
+},
+{   .name="arimo",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}
+},
+{   .name="baskerville",
+    .brightness={on, 0, -20, end},
+    .contrast={on, 0, 25, end}
+},
+{   .name="bitstream vera sans mono",
+    .always_use_100={on, 0, maxp, end}
+},
+{   .name="bitstream vera sans",
+    .always_use_100={on, 10, 14, 16, 17, end},
+    .m={on, 12, 0, end},
+    .stem_scaling={on ,12, 1, end},
+    .stem_translating_only={on, 8, 16, end}
+},
+{   .name="calibri",
+    .always_use_100={on, 23, maxp, end},
+    .stem_scaling={on, 15, 1, 17, 1, 18, 1, end},
+    .stem_translating_only={on, 10, 16, 15, 0, end},
+    .stem_widths={on, 1, 10, 19, maxp,}
+},
+{   .name="candara",
+    .stem_scaling={on, 14, 1, 17, 1, end},
+    .stem_translating_only={on, 10, 16, end}
+},
+{   .name="cantarell",
+    .stem_translating_only={on, 11, 0, 12, 0, end},
+    .stem_widths={on, 10, 22, maxp,}
+},
+{   .name="canwell",
+    .stem_scaling={on, 13, 0, end}
+},
+{   .name="century gothic",
+    .stem_widths={on, 10, 22, maxp,}
+},
+{   .name="comfortaa",
+    .stem_widths={on, 10, 19, 22, maxp},
+    .stem_scaling={on, 11, 0, end}
+},
+{   .name="consolas",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating_only={on, 8, 32, 9, 32, end},
+    .stem_widths={on, 10, 20, maxp,},
+    .stem_scaling={on, 11, 1, end}
+},
+{   .name="corbel",
+    .stem_translating_only={on, 10, 16, end},
+    .stem_widths={on, 10, 21, maxp}
+},
+{   .name="courier new",
+    .always_use_100={on, 12, 12, end},
+    .edge_detection={on, 10, 12, end},
+    .m={on, 13, 1, 14, 1, end}
+},
+{   .name="courier",
+    .always_use_100={on, 0, maxp, end},
+    .m={on, 13, 1, 14, 1, end},
+    .stem_translating_only={on, 13, 16, 15, 0, end}
+},
+{   .name="cousine",
+    .always_use_100={on, 0, maxp, end}
+},
+{   .name="dejavu sans mono",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end}
+},
+{   .name="dejavu sans",
+    .always_use_100={on, 10, 14, 16, 17, end},
+    .m={on, 12, 0, end},
+    .stem_scaling={on, 12, 1, end},
+    .stem_translating_only={on, 8, 16, 15, -20, end}
+},
+{   .name="droid sans mono",
+    .m={on, 12, 0, end}
+},
+{   .name="droid sans",
+    .always_use_100={on, 12, 12, 15, 15, end},
+    .stem_translating_only={on, 8, 16, 9, 16, end}
+},
+{   .name="essential pragmatapro",
+    .always_use_100={on, 0, maxp, end},
+    .m={on, 13, 0, 14, 0, end}
+},
+{   .name="freemono",
+    .always_use_100={on, 0, maxp, end}
+},
+{   .name="freesans",
+    .always_use_100={on, 0, maxp, end},
+    .edge_detection={on, 11, 11, 13, 13, end},
+    .spacing={on, 10, 12, 18, 18, 30, end},
+    .start={on, 10, 18, 18, 25, 30, end},
+    .stem_scaling={on, 16, 0, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 16, 9, 8, end}
+},
+{   .name="freeserif",
+    .stem_scaling={on, 13, 1, 17, 1, end}
+},
+{   .name="futura",
+    .stem_widths={on, 10, 14, sw2pv, maxp,}
+},
+{   .name="garamond",
+    .brightness={on, 0, -20, end},
+    .contrast={on, 0, 25, end}
+},
+{   .name="georgia",
+    .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end}
+},
+{   .name="gill sans",
+    .stem_widths={on, 10, 17, sw2pv, maxp,}
+},
+{   .name="helvetica cy",
+    .stem_widths={on, 10, 23, maxp,}
+},
+{   .name="inconsolata",
+    .stem_scaling={on, 12, 1, 15, 1, end},
+    .stem_translating_only={on, 10, 24, 9, 32, end},
+    .stem_widths={on, 10, 23, maxp,},
+},
+{   .name="liberation mono",
+    .always_use_100={on, 0, maxp, end}
+},
+{   .name="liberation sans narrow",
+    .stem_widths={on,10, 22, maxp,}
+},
+{   .name="liberation sans",
+    .edge_detection={on, 11, 11, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end},
+    .stem_widths={on,10, 19, maxp,}
+},
+{   .name="lucida console",
+    .always_use_100={on, 0, maxp, end}
+},
+{   .name="lucida grande",
+    .stem_scaling={on, 13, 1, end},
+    .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
+    .stem_widths={on, 10, 16, sw2pv, maxp},
+},
+{   .name="lucida sans unicode",
+    .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end},
+    .stem_widths={on,10, 16, sw2pv, maxp,}
+},
+{   .name="luxi sans",
+    .always_use_100={on, 13, 13, end},
+    .stem_widths={on, 10, 17, sw2pv, maxp,}
+},
+{   .name="microsoft sans serif",
+    .always_use_100={on, 0, maxp, end},
+    .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end}
+},
+{   .name="monaco",
+    .always_use_100={on, 0, maxp, end}
+},
+{   .name="myriad pro",
+    .stem_scaling={on, 14, 1, 17, 1, end},
+    .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end}
+},
+{   .name="nina",
+    .stem_scaling={on, 11, 0, 12, 0, 13, 0, end}
+},
+{   .name="open sans",
+    .stem_translating_only={on, 10, 16, 9, 16, end},
+    .stem_widths={on, 10, 20, maxp,}
+},
+{   .name="optima",
+    .brightness={on, 0, -20, end},
+    .contrast={on, 0, 25, end},
+    .stem_scaling={on, 17, 1, end},
+    .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end}
+},
+{   .name="palatino linotype",
+    .edge_detection={on, 0, 100, end}
+},
+{   .name="pragmata",
+    .always_use_100={on, 0, maxp, end}
+},
+{   .name="raleway",
+    .stem_scaling={on, 15, 0, end}
+},
+{   .name="rokkitt",
+    .stem_widths={on, 10, 21, maxp,}
+},
+{   .name="samba",
+    .stem_scaling={on, 11, 0, end}
+},
+{   .name="segoe ui",
+    .always_use_100={on, 11, 12, 14, 14, end},
+    .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end},
+    .stem_widths={on, 10, 23, maxp,}
+},
+{   .name="tahoma",
+    .always_use_100={on, 11, 11, 14, maxp, end},
+    .edge_detection={on, 11, 11, end},
+    .spacing={on, 10, 12, 18, 18, 30, end},
+    .start={on, 14, 17, 30, 100, 100, end},
+    .stem_translating={on, 11, 32, end},
+    .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end},
+},
+{   .name="times new roman",
+    .always_use_100={on, 14, 14, 16, 16, end},
+    .bearing_correction={0, 100, end},
+    .stem_scaling={on, 17, 1, end},
+    .stem_translating_only={on, 17, 8, end}
+},
+{   .name="trebuchet ms",
+    .always_use_100={on, 13, 13, end},
+    .stem_scaling={on, 13, 0, 17, 0, 20, 1, end},
+    .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end},
+    .stem_widths={on, 10, 17, sw2pv, maxp,}
+},
+{   .name="ubuntu",
+    .always_use_100={on, 12, 13, 15, 15, end}
+},
+{   .name="verdana",
+    .always_use_100={on, 0, 14, 16, maxp, end},
+    .stem_scaling={on, 12, 1, 15, 1, end},
+    .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end}
+},
+%%
+
+static const sa_rules_t*
+ftinf_rules( const char *name ){
+    if( name ){
+        enum {
+            max_wlen=31
+        };
+        char buf[max_wlen+1];
+        int len=strlen( name );
+        if( len <= max_wlen ){
+            int i;
+            for( i=0; i<len; ++i )
+                buf[i]=tolower( name[i] );
+            buf[len]='\0';
+            return _rules_get( buf, len );
+        }
+    }
+    return NULL;
+}
+/*
+   gperf --output-file=ftinf_rh.c ftinf_rh.gperf
+*/
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_sh.c a/src/base/ftinf_sh.c
--- b/src/base/ftinf_sh.c	1970-01-01 03:00:00.000000000 +0300
+++ a/src/base/ftinf_sh.c	2021-09-16 09:15:05.052379743 +0300
@@ -0,0 +1,463 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf --output-file=ftinf_sh.c ftinf_sh.gperf  */
+/* Computed positions: -k'1,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 9 "ftinf_sh.gperf"
+
+#include <ctype.h>
+static const struct ftinf_s* _settings_get( const char*str, unsigned len);
+/* maximum key range = 37, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+_settings_hash (register const char *str, register unsigned int len)
+{
+  static const unsigned char asso_values[] =
+    {
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 13,
+       8, 30, 25, 20, 40, 10, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40,  5, 40,  0,
+       0,  0, 40, 40, 10,  0, 40, 40, 15,  5,
+      10,  0, 10, 40, 40,  0,  0,  0,  0,  0,
+       0,  0, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 40, 40, 40, 40, 40
+    };
+  return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
+}
+
+#ifdef __GNUC__
+__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const struct ftinf_s *
+_settings_get (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 22,
+      MIN_WORD_LENGTH = 3,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 3,
+      MAX_HASH_VALUE = 39
+    };
+
+  static const struct ftinf_s wordlist[] =
+    {
+#line 76 "ftinf_sh.gperf"
+{   .name="osx",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_vertical_stem_darken_strength=25,
+    .bold_embolden_x_value=16,
+    .brightness=10,
+    .contrast=20,
+    .filter_params={on, 3, 32, 38, 32, 3},
+    .gamma_correction={1000, 80},
+    .global_embolden_y_value=8,
+    .grayscale_filter_strength=25,
+},
+#line 37 "ftinf_sh.gperf"
+{   .name="ipad",
+    .filter_params={on, 0, 0, 100, 0, 0},
+    .gamma_correction={1000, 80},
+    .grayscale_filter_strength=100
+},
+#line 114 "ftinf_sh.gperf"
+{   .name="shove",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=100,
+    .stem_fitting_strength=100,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true
+},
+#line 126 "ftinf_sh.gperf"
+{   .name="ubuntu",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_vertical_stem_darken_strength=25,
+    .brightness=-10,
+    .contrast=15,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={1000, 80},
+    .use_various_tweaks=true
+},
+#line 27 "ftinf_sh.gperf"
+{   .name="classic",
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .filter_params={on, 6, 25, 38, 25, 6},
+    .gamma_correction={0, 100},
+    .use_various_tweaks=true
+},
+#line 34 "ftinf_sh.gperf"
+{   .name="disabled",
+    .gamma_correction={0, 100},
+},
+#line 100 "ftinf_sh.gperf"
+{   .name="sharpened",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=25,
+    .stem_fitting_strength=25,
+    .stem_snapping_sliding_scale=40,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=65
+},
+#line 42 "ftinf_sh.gperf"
+{   .name="infinality",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=25,
+    .stem_fitting_strength=25,
+    .stem_snapping_sliding_scale=40,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=5
+},
+#line 15 "ftinf_sh.gperf"
+{   .name="custom",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 8, 24, 48, 24, 8},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=75,
+    .stem_fitting_strength=50,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true
+},
+#line 180 "ftinf_sh.gperf"
+{   .name="vanilla",
+    .filter_params={on, 6, 25, 38, 25, 6},
+    .gamma_correction={0, 100},
+},
+#line 184 "ftinf_sh.gperf"
+{   .name="windows7light",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .contrast=20,
+    .filter_params={on, 20, 25, 38, 25, 05},
+    .fringe_filter_strength=100,
+    .gamma_correction={1000, 160},
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=100
+},
+#line 226 "ftinf_sh.gperf"
+{   .name="windowsxplight",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .brightness=20,
+    .contrast=30,
+    .filter_params={on, 6, 25, 44, 25, 6},
+    .fringe_filter_strength=100,
+    .gamma_correction={1000, 120},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=65
+},
+#line 64 "ftinf_sh.gperf"
+{   .name="nudge",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=25,
+    .stem_fitting_strength=15,
+    .stem_snapping_sliding_scale=30,
+    .use_various_tweaks=true,
+},
+#line 144 "ftinf_sh.gperf"
+{   .name="ultimate2",
+    .filter_params={on, 6, 22, 36, 22, 6},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+#line 197 "ftinf_sh.gperf"
+{   .name="windows7",
+    .filter_params={on, 20, 25, 42, 25, 06},
+    .fringe_filter_strength=100,
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_vertical_stem_darken_strength=25,
+    .windows_style_sharpening_strength=65,
+    .gamma_correction={1000, 120},
+    .brightness=10,
+    .contrast=20,
+    .use_various_tweaks=true,
+    .autohint_snap_stem_height=100,
+    .use_known_settings_on_selected_fonts=true,
+},
+#line 210 "ftinf_sh.gperf"
+{   .name="windowsxp",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .brightness=10,
+    .contrast=20,
+    .filter_params={on, 6, 25, 44, 25, 6},
+    .fringe_filter_strength=100,
+    .gamma_correction={1000, 120},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=65
+},
+#line 56 "ftinf_sh.gperf"
+{   .name="linux",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 6, 25, 44, 25, 6},
+    .gamma_correction={0, 100},
+    .use_various_tweaks=true
+},
+#line 135 "ftinf_sh.gperf"
+{   .name="ultimate1",
+    .filter_params={on, 4, 22, 38, 22, 4},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+#line 87 "ftinf_sh.gperf"
+{   .name="push",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=75,
+    .stem_fitting_strength=50,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true
+},
+#line 171 "ftinf_sh.gperf"
+{   .name="ultimate5",
+    .filter_params={on, 12, 28, 42, 28, 12},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+#line 162 "ftinf_sh.gperf"
+{   .name="ultimate4",
+    .filter_params={on, 10, 25, 37, 25, 10},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+#line 153 "ftinf_sh.gperf"
+{   .name="ultimate3",
+    .filter_params={on, 8, 24, 36, 24, 8},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = _settings_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
+        {
+          register const struct ftinf_s *resword;
+
+          switch (key - 3)
+            {
+              case 0:
+                resword = &wordlist[0];
+                goto compare;
+              case 1:
+                resword = &wordlist[1];
+                goto compare;
+              case 2:
+                resword = &wordlist[2];
+                goto compare;
+              case 3:
+                resword = &wordlist[3];
+                goto compare;
+              case 4:
+                resword = &wordlist[4];
+                goto compare;
+              case 5:
+                resword = &wordlist[5];
+                goto compare;
+              case 6:
+                resword = &wordlist[6];
+                goto compare;
+              case 7:
+                resword = &wordlist[7];
+                goto compare;
+              case 8:
+                resword = &wordlist[8];
+                goto compare;
+              case 9:
+                resword = &wordlist[9];
+                goto compare;
+              case 10:
+                resword = &wordlist[10];
+                goto compare;
+              case 11:
+                resword = &wordlist[11];
+                goto compare;
+              case 12:
+                resword = &wordlist[12];
+                goto compare;
+              case 14:
+                resword = &wordlist[13];
+                goto compare;
+              case 15:
+                resword = &wordlist[14];
+                goto compare;
+              case 16:
+                resword = &wordlist[15];
+                goto compare;
+              case 17:
+                resword = &wordlist[16];
+                goto compare;
+              case 19:
+                resword = &wordlist[17];
+                goto compare;
+              case 21:
+                resword = &wordlist[18];
+                goto compare;
+              case 26:
+                resword = &wordlist[19];
+                goto compare;
+              case 31:
+                resword = &wordlist[20];
+                goto compare;
+              case 36:
+                resword = &wordlist[21];
+                goto compare;
+            }
+          return 0;
+        compare:
+          {
+            register const char *s = resword->name;
+
+            if (*str == *s && !strcmp (str + 1, s + 1))
+              return resword;
+          }
+        }
+    }
+  return 0;
+}
+#line 242 "ftinf_sh.gperf"
+
+
+static const ftinf_t*
+ftinf_settings( const char *name ){
+    if( name ){
+        enum {
+            max_wlen=31
+        };
+        char buf[max_wlen+1];
+        int len=strlen( name );
+        if( len <= max_wlen ){
+            int i;
+            for( i=0; i<len; ++i )
+                buf[i]=tolower( name[i] );
+            buf[len]='\0';
+            return _settings_get( buf, len );
+        }
+    }
+    return NULL;
+}
+/*
+   gperf --output-file=ftinf_sh.c ftinf_sh.gperf
+*/
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinf_sh.gperf a/src/base/ftinf_sh.gperf
--- b/src/base/ftinf_sh.gperf	1970-01-01 03:00:00.000000000 +0300
+++ a/src/base/ftinf_sh.gperf	2021-09-16 09:15:05.052379743 +0300
@@ -0,0 +1,264 @@
+%struct-type
+%define slot-name name
+%enum
+%switch=1
+%readonly-tables
+%omit-struct-type
+%define lookup-function-name   _settings_get
+%define hash-function-name _settings_hash
+%{
+#include <ctype.h>
+static const struct ftinf_s* _settings_get( const char*str, unsigned len);
+%}
+struct ftinf_s;
+%%
+{   .name="custom",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 8, 24, 48, 24, 8},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=75,
+    .stem_fitting_strength=50,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true
+},
+{   .name="classic",
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .filter_params={on, 6, 25, 38, 25, 6},
+    .gamma_correction={0, 100},
+    .use_various_tweaks=true
+},
+{   .name="disabled",
+    .gamma_correction={0, 100},
+},
+{   .name="ipad",
+    .filter_params={on, 0, 0, 100, 0, 0},
+    .gamma_correction={1000, 80},
+    .grayscale_filter_strength=100
+},
+{   .name="infinality",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=25,
+    .stem_fitting_strength=25,
+    .stem_snapping_sliding_scale=40,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=5
+},
+{   .name="linux",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 6, 25, 44, 25, 6},
+    .gamma_correction={0, 100},
+    .use_various_tweaks=true
+},
+{   .name="nudge",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=25,
+    .stem_fitting_strength=15,
+    .stem_snapping_sliding_scale=30,
+    .use_various_tweaks=true,
+},
+{   .name="osx",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_vertical_stem_darken_strength=25,
+    .bold_embolden_x_value=16,
+    .brightness=10,
+    .contrast=20,
+    .filter_params={on, 3, 32, 38, 32, 3},
+    .gamma_correction={1000, 80},
+    .global_embolden_y_value=8,
+    .grayscale_filter_strength=25,
+},
+{   .name="push",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=75,
+    .stem_fitting_strength=50,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true
+},
+{   .name="sharpened",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=25,
+    .stem_fitting_strength=25,
+    .stem_snapping_sliding_scale=40,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=65
+},
+{   .name="shove",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_increase_glyph_heights=true,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=100,
+    .stem_fitting_strength=100,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true
+},
+{   .name="ubuntu",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_vertical_stem_darken_strength=25,
+    .brightness=-10,
+    .contrast=15,
+    .filter_params={on, 11, 22, 38, 22, 11},
+    .gamma_correction={1000, 80},
+    .use_various_tweaks=true
+},
+{   .name="ultimate1",
+    .filter_params={on, 4, 22, 38, 22, 4},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+{   .name="ultimate2",
+    .filter_params={on, 6, 22, 36, 22, 6},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+{   .name="ultimate3",
+    .filter_params={on, 8, 24, 36, 24, 8},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+{   .name="ultimate4",
+    .filter_params={on, 10, 25, 37, 25, 10},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+{   .name="ultimate5",
+    .filter_params={on, 12, 28, 42, 28, 12},
+    .fringe_filter_strength=25,
+    .gamma_correction={0, 100},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=25
+},
+{   .name="vanilla",
+    .filter_params={on, 6, 25, 38, 25, 6},
+    .gamma_correction={0, 100},
+},
+{   .name="windows7light",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .contrast=20,
+    .filter_params={on, 20, 25, 38, 25, 05},
+    .fringe_filter_strength=100,
+    .gamma_correction={1000, 160},
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=100
+},
+{   .name="windows7",
+    .filter_params={on, 20, 25, 42, 25, 06},
+    .fringe_filter_strength=100,
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_vertical_stem_darken_strength=25,
+    .windows_style_sharpening_strength=65,
+    .gamma_correction={1000, 120},
+    .brightness=10,
+    .contrast=20,
+    .use_various_tweaks=true,
+    .autohint_snap_stem_height=100,
+    .use_known_settings_on_selected_fonts=true,
+},
+{   .name="windowsxp",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .brightness=10,
+    .contrast=20,
+    .filter_params={on, 6, 25, 44, 25, 6},
+    .fringe_filter_strength=100,
+    .gamma_correction={1000, 120},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=65
+},
+{   .name="windowsxplight",
+    .autohint_horizontal_stem_darken_strength=10,
+    .autohint_snap_stem_height=100,
+    .autohint_vertical_stem_darken_strength=25,
+    .brightness=20,
+    .contrast=30,
+    .filter_params={on, 6, 25, 44, 25, 6},
+    .fringe_filter_strength=100,
+    .gamma_correction={1000, 120},
+    .stem_alignment_strength=15,
+    .stem_fitting_strength=15,
+    .stem_snapping_sliding_scale=30,
+    .use_known_settings_on_selected_fonts=true,
+    .use_various_tweaks=true,
+    .windows_style_sharpening_strength=65
+},
+%%
+
+static const ftinf_t*
+ftinf_settings( const char *name ){
+    if( name ){
+        enum {
+            max_wlen=31
+        };
+        char buf[max_wlen+1];
+        int len=strlen( name );
+        if( len <= max_wlen ){
+            int i;
+            for( i=0; i<len; ++i )
+                buf[i]=tolower( name[i] );
+            buf[len]='\0';
+            return _settings_get( buf, len );
+        }
+    }
+    return NULL;
+}
+/*
+   gperf --output-file=ftinf_sh.c ftinf_sh.gperf
+*/
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftinit.c a/src/base/ftinit.c
--- b/src/base/ftinit.c	2021-02-13 10:16:54.000000000 +0200
+++ a/src/base/ftinit.c	2021-09-16 09:15:05.052379743 +0300
@@ -43,6 +43,10 @@
 #include <freetype/internal/ftdebug.h>
 #include <freetype/ftmodapi.h>
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "ftinf.h"
+#endif
+
 
   /**************************************************************************
    *
@@ -224,10 +228,14 @@
     error = FT_New_Library( memory, alibrary );
     if ( error )
       FT_Done_Memory( memory );
-    else
+    else {
       FT_Add_Default_Modules( *alibrary );
-
     FT_Set_Default_Properties( *alibrary );
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      /* get Infinality settings */
+      ftinf_env();
+#endif
+    }
 
     return error;
   }
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftlcdfil.c a/src/base/ftlcdfil.c
--- b/src/base/ftlcdfil.c	2021-07-05 06:41:53.000000000 +0300
+++ a/src/base/ftlcdfil.c	2021-09-16 09:15:05.052379743 +0300
@@ -17,11 +17,15 @@
 
 
 #include <freetype/internal/ftdebug.h>
-
 #include <freetype/ftlcdfil.h>
 #include <freetype/ftimage.h>
 #include <freetype/internal/ftobjs.h>
 
+#include <math.h>
+#include <string.h>
+#include <strings.h>
+#include "ftinf.h"
+
 
 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 
@@ -76,13 +80,13 @@
   /* FIR filter used by the default and light filters */
   FT_BASE_DEF( void )
   ft_lcd_filter_fir( FT_Bitmap*           bitmap,
+                     FT_Render_Mode       mode,
                      FT_LcdFiveTapFilter  weights )
   {
     FT_UInt   width  = (FT_UInt)bitmap->width;
     FT_UInt   height = (FT_UInt)bitmap->rows;
     FT_Int    pitch  = bitmap->pitch;
     FT_Byte*  origin = bitmap->buffer;
-    FT_Byte   mode   = bitmap->pixel_mode;
 
 
     /* take care of bitmap flow */
@@ -90,7 +94,7 @@
       origin += pitch * (FT_Int)( height - 1 );
 
     /* horizontal in-place FIR filter */
-    if ( mode == FT_PIXEL_MODE_LCD && width >= 2 )
+    if ( mode == FT_RENDER_MODE_LCD && width >= 2 )
     {
       FT_Byte*  line = origin;
 
@@ -133,7 +137,7 @@
     }
 
     /* vertical in-place FIR filter */
-    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 )
+    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 2 )
     {
       FT_Byte*  column = origin;
 
@@ -182,13 +186,13 @@
   /* intra-pixel filter used by the legacy filter */
   static void
   _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
+                         FT_Render_Mode  mode,
                          FT_Byte*        weights )
   {
     FT_UInt   width  = (FT_UInt)bitmap->width;
     FT_UInt   height = (FT_UInt)bitmap->rows;
     FT_Int    pitch  = bitmap->pitch;
     FT_Byte*  origin = bitmap->buffer;
-    FT_Byte   mode   = bitmap->pixel_mode;
 
     static const unsigned int  filters[3][3] =
     {
@@ -205,7 +209,7 @@
       origin += pitch * (FT_Int)( height - 1 );
 
     /* horizontal in-place intra-pixel filter */
-    if ( mode == FT_PIXEL_MODE_LCD && width >= 3 )
+    if ( mode == FT_RENDER_MODE_LCD && width >= 3 )
     {
       FT_Byte*  line = origin;
 
@@ -242,7 +246,7 @@
         }
       }
     }
-    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 )
+    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 )
     {
       FT_Byte*  column = origin;
 
@@ -298,6 +302,7 @@
 
     ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
     library->lcd_filter_func = ft_lcd_filter_fir;
+    library->lcd_extra       = 2;
 
     return FT_Err_Ok;
   }
@@ -309,11 +314,37 @@
   FT_Library_SetLcdFilter( FT_Library    library,
                            FT_LcdFilter  filter )
   {
-    static const FT_LcdFiveTapFilter  default_weights =
-                   { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
     static const FT_LcdFiveTapFilter  light_weights =
                    { 0x00, 0x55, 0x56, 0x55, 0x00 };
 
+#ifndef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    static const FT_LcdFiveTapFilter  default_weights =
+                   { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
+#else
+    FT_LcdFiveTapFilter default_weights;
+    if( ftinf && ftinf->filter_params[0] )
+    {
+        const int *f=ftinf->filter_params;
+        /* Assume we were given integers [0-100] get them to [0-255] */
+        int val; /* 2611=2.55*1024 */
+        val=(f[1]*2611+512)>>10; if( val > 255 ) val=255;
+        default_weights[0] = (FT_Byte) val;
+        val=(f[2]*2611+512)>>10; if( val > 255 ) val=255;
+        default_weights[1] = (FT_Byte) val;
+        val=(f[3]*2611+512)>>10; if( val > 255 ) val=255;
+        default_weights[2] = (FT_Byte) val;
+        val=(f[4]*2611+512)>>10; if( val > 255 ) val=255;
+        default_weights[3] = (FT_Byte) val;
+        val=(f[5]*2611+512)>>10; if( val > 255 ) val=255;
+        default_weights[4] = (FT_Byte) val;
+    } else {
+        default_weights[0]=0x08;
+        default_weights[1]=0x4d;
+        default_weights[2]=0x56;
+        default_weights[3]=0x4d;
+        default_weights[4]=0x08;
+    }
+#endif
 
     if ( !library )
       return FT_THROW( Invalid_Library_Handle );
@@ -322,6 +353,7 @@
     {
     case FT_LCD_FILTER_NONE:
       library->lcd_filter_func = NULL;
+      library->lcd_extra       = 0;
       break;
 
     case FT_LCD_FILTER_DEFAULT:
@@ -329,6 +361,7 @@
                  default_weights,
                  FT_LCD_FILTER_FIVE_TAPS );
       library->lcd_filter_func = ft_lcd_filter_fir;
+      library->lcd_extra       = 2;
       break;
 
     case FT_LCD_FILTER_LIGHT:
@@ -336,6 +369,7 @@
                  light_weights,
                  FT_LCD_FILTER_FIVE_TAPS );
       library->lcd_filter_func = ft_lcd_filter_fir;
+      library->lcd_extra       = 2;
       break;
 
 #ifdef USE_LEGACY
@@ -343,6 +377,7 @@
     case FT_LCD_FILTER_LEGACY:
     case FT_LCD_FILTER_LEGACY1:
       library->lcd_filter_func = _ft_lcd_filter_legacy;
+      library->lcd_extra       = 0;
       break;
 
 #endif
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftobjs.c a/src/base/ftobjs.c
--- b/src/base/ftobjs.c	2021-07-15 13:09:04.000000000 +0300
+++ a/src/base/ftobjs.c	2021-09-16 09:15:05.053379751 +0300
@@ -45,7 +45,9 @@
 #ifdef FT_CONFIG_OPTION_MAC_FONTS
 #include "ftbase.h"
 #endif
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "ftinf.h"
+#endif
 
 #ifdef FT_DEBUG_LEVEL_TRACE
 
@@ -99,6 +101,11 @@
 
 #define GRID_FIT_METRICS
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include <strings.h>
+#include <stdlib.h>
+#include "../autofit/aflatin.h"
+#endif
 
   /* forward declaration */
   static FT_Error
@@ -777,6 +784,25 @@
   ft_lookup_glyph_renderer( FT_GlyphSlot  slot );
 
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+  static void
+  ft_glyphslot_enlarge_metrics( FT_GlyphSlot slot,
+                                FT_Render_Mode mode )
+  {
+    FT_Glyph_Metrics*  metrics = &slot->metrics;
+    FT_Pos enlarge_cbox = 0;
+
+
+    /* enlarge for grayscale rendering */
+    if ( mode == FT_RENDER_MODE_NORMAL )
+      enlarge_cbox = 64;
+
+    metrics->horiBearingX -= enlarge_cbox;
+    metrics->width += 2 * enlarge_cbox;
+  }
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+
 #ifdef GRID_FIT_METRICS
   static void
   ft_glyphslot_grid_fit_metrics( FT_GlyphSlot  slot,
@@ -843,8 +869,18 @@
     FT_Bool       autohint = FALSE;
     FT_Module     hinter;
     TT_Face       ttface = (TT_Face)face;
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
 
+    FT_Bool use_various_tweaks = FALSE;
+    if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
 
+    /* Force autohint if no tt instructions */
+    /* NOTE:  NEEDS TO BE RUN LATER IN CODE???? */
+    /*if ( use_various_tweaks                             &&
+         ttface->num_locations                          &&
+         ttface->max_profile.maxSizeOfInstructions == 0 )
+      load_flags |= FT_LOAD_FORCE_AUTOHINT;*/
+#endif
     if ( !face || !face->size || !face->glyph )
       return FT_THROW( Invalid_Face_Handle );
 
@@ -946,6 +982,18 @@
     {
       FT_AutoHinter_Interface  hinting;
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      if ( use_various_tweaks )
+      {
+        /* Force slight hinting over full hinting always */
+        load_flags &= ~FT_LOAD_TARGET_LCD;
+        load_flags &= ~FT_LOAD_TARGET_LCD_V;
+        load_flags &= ~FT_LOAD_TARGET_MONO;
+        load_flags &= ~FT_LOAD_TARGET_NORMAL;
+        load_flags |= FT_LOAD_TARGET_LIGHT;
+        /*printf("%d ", load_flags);*/
+      }
+#endif
 
       /* try to load embedded bitmaps first if available            */
       /*                                                            */
@@ -991,6 +1039,18 @@
       if ( error )
         goto Exit;
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      infinality_cur_width = 0;
+
+      {
+        /* fix for sdl_ttf */
+        FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
+
+        if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+          ft_glyphslot_enlarge_metrics( slot, mode );
+      }
+#endif
+
       if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
       {
         /* check that the loaded outline is correct */
@@ -5353,6 +5413,11 @@
     /* That's ok now */
     *alibrary = library;
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    /* get Infinality settings */
+    ftinf_env();
+#endif
+
     return FT_Err_Ok;
   }
 
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftoutln.c a/src/base/ftoutln.c
--- b/src/base/ftoutln.c	2021-02-13 10:16:54.000000000 +0200
+++ a/src/base/ftoutln.c	2021-09-16 09:15:05.053379751 +0300
@@ -22,6 +22,9 @@
 #include <freetype/internal/ftdebug.h>
 #include <freetype/fttrigon.h>
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "ftinf.h"
+#endif
 
   /**************************************************************************
    *
@@ -907,8 +910,14 @@
   {
     FT_Vector*      points;
     FT_Int          c, first, last;
-    FT_Orientation  orientation;
-
+    FT_Int      orientation;
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    FT_Bool use_various_tweaks = FALSE;
+    if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
+
+    if ( use_various_tweaks )
+      ystrength = FT_PIX_FLOOR ( ystrength );
+#endif
 
     if ( !outline )
       return FT_THROW( Invalid_Outline );
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/ftsynth.c a/src/base/ftsynth.c
--- b/src/base/ftsynth.c	2021-02-13 10:16:54.000000000 +0200
+++ a/src/base/ftsynth.c	2021-09-16 09:15:05.053379751 +0300
@@ -22,6 +22,9 @@
 #include <freetype/ftoutln.h>
 #include <freetype/ftbitmap.h>
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "ftinf.h"
+#endif
 
   /**************************************************************************
    *
@@ -92,7 +95,10 @@
     FT_Face     face;
     FT_Error    error;
     FT_Pos      xstr, ystr;
-
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    FT_Bool use_various_tweaks = FALSE;
+    if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks;
+#endif
 
     if ( !slot )
       return;
@@ -110,8 +116,16 @@
     ystr = xstr;
 
     if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+    {
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      if ( use_various_tweaks )
+        (void)FT_Outline_EmboldenXY( &slot->outline,
+                                     xstr,
+                                     FT_PIX_FLOOR( ystr ) );
+      else
+#endif
       FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
-
+    }
     else /* slot->format == FT_GLYPH_FORMAT_BITMAP */
     {
       /* round to full pixels */
@@ -149,6 +163,9 @@
 
     slot->metrics.width        += xstr;
     slot->metrics.height       += ystr;
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    if ( !use_various_tweaks )
+#endif
     slot->metrics.horiAdvance  += xstr;
     slot->metrics.vertAdvance  += ystr;
     slot->metrics.horiBearingY += ystr;
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/base/rules.mk a/src/base/rules.mk
--- b/src/base/rules.mk	2021-02-13 10:16:54.000000000 +0200
+++ a/src/base/rules.mk	2021-09-16 09:15:05.053379751 +0300
@@ -44,6 +44,7 @@
             $(BASE_DIR)/ftfntfmt.c \
             $(BASE_DIR)/ftgloadr.c \
             $(BASE_DIR)/fthash.c   \
+            $(BASE_DIR)/ftinf.c    \
             $(BASE_DIR)/ftlcdfil.c \
             $(BASE_DIR)/ftobjs.c   \
             $(BASE_DIR)/ftoutln.c  \
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/cff/cffobjs.c a/src/cff/cffobjs.c
--- b/src/cff/cffobjs.c	2021-02-13 10:16:54.000000000 +0200
+++ a/src/cff/cffobjs.c	2021-09-16 09:15:05.053379751 +0300
@@ -42,6 +42,9 @@
 #include <freetype/internal/psaux.h>
 #include <freetype/internal/services/svcfftl.h>
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include "../base/ftinf.h"
+#endif
 
   /**************************************************************************
    *
@@ -1177,6 +1180,9 @@
     driver->hinting_engine = FT_HINTING_ADOBE;
 
     driver->no_stem_darkening = TRUE;
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    if(ftinf) driver->no_stem_darkening = !ftinf->stem_darkening_cff;
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
 
     driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
     driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
diff -Nbur --exclude builds --exclude '*.orig' --exclude objs b/src/smooth/ftsmooth.c a/src/smooth/ftsmooth.c
--- b/src/smooth/ftsmooth.c	2021-02-13 10:16:54.000000000 +0200
+++ a/src/smooth/ftsmooth.c	2021-09-16 09:19:36.749340217 +0300
@@ -24,6 +24,28 @@
 
 #include "ftsmerrs.h"
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+#include <math.h>
+#include FT_BITMAP_H
+#include <string.h>
+#include <strings.h>
+#include FT_OUTLINE_H
+#include "../base/ftinf.h"
+
+#define verbose FALSE
+#define STVALUES if (verbose) \
+  printf ( "scale:%f translate:%ld ", *scale_value, *translate_value );
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
+
+  /* initialize renderer -- init its raster */
+  static FT_Error
+  ft_smooth_init( FT_Renderer  render )
+  {
+    render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
+
+    return 0;
+  }
+
 
   /* sets render-specific mode */
   static FT_Error
@@ -76,367 +98,2440 @@
       FT_Outline_Get_CBox( &slot->outline, cbox );
   }
 
-  typedef struct TOrigin_
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+  static FT_Fixed FT_FixedFromFloat(float f)
   {
-    unsigned char*  origin;  /* pixmap origin at the bottom-left */
-    int             pitch;   /* pitch to go down one row */
+    short          value = f;
+    unsigned short fract = (f - value) * 0xFFFF;
 
-  } TOrigin;
 
-#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    return (FT_Fixed)((long)value << 16 | (unsigned long)fract );
+  }
 
-  /* initialize renderer -- init its raster */
-  static FT_Error
-  ft_smooth_init( FT_Renderer  render )
+
+  /* ChromeOS sharpening algorithm */
+  /* soften the sub-pixel anti-aliasing and sharpen */
+  static void
+  _ft_lcd_chromeos_sharpen( FT_Bitmap*  bitmap,
+                        FT_Render_Mode  mode,
+                        FT_Byte         cutoff,
+                        double          gamma_value )
+  {
+    static FT_Bool        initialized_gamma = FALSE;
+    static unsigned short gamma_ramp[256];
+    FT_UInt               width  = (FT_UInt)bitmap->width;
+    FT_UInt               height = (FT_UInt)bitmap->rows;
+    int    ii;
+
+    if ( !initialized_gamma )
+    {
+      initialized_gamma = TRUE;
+      /* linear to voltage */
+      for ( ii = 0; ii < 256; ii++ )
+      {
+        gamma_ramp[ii] = (unsigned char)
+                         ( pow( (double)ii / 255.0, gamma_value ) * 255.0f );
+        if ( gamma_ramp[ii] < cutoff )
+          gamma_ramp[ii] = 0;
+      }
+    }
+
+    /* horizontal in-place sub-pixel sharpening filter */
+    if ( mode == FT_RENDER_MODE_LCD )
   {
-    FT_Vector*  sub = render->root.library->lcd_geometry;
+      FT_Byte*  line = bitmap->buffer;
 
 
-    /* set up default subpixel geometry for striped RGB panels. */
-    sub[0].x = -21;
-    sub[0].y = 0;
-    sub[1].x = 0;
-    sub[1].y = 0;
-    sub[2].x = 21;
-    sub[2].y = 0;
+      for ( ; height > 0; height--, line += bitmap->pitch )
+      {
+        FT_UInt  xx;
 
-    render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
 
-    return 0;
+        for ( xx = 0; xx < width; xx++ )
+          line[xx] = gamma_ramp[line[xx]];
+      }
+    }
+  }
+
+  /* simple linear scale to handle various sliding values */
+  float
+  sliding_scale ( int            min_value,
+                      int        max_value,
+                      float      min_amount,
+                      float      max_amount,
+                      int        cur_value )
+  {
+
+    float m = ( min_amount - max_amount ) / (float)( min_value - max_value );
+    float result = ( ( (float)cur_value * m) + ( max_amount - max_value * m ) ) ;
+
+    if ( min_amount < max_amount )
+    {
+      if ( result < min_amount )
+        return min_amount;
+      if ( result > max_amount )
+        return max_amount;
+    }
+    else
+    {
+      if ( result < max_amount )
+        return max_amount;
+      if ( result > min_amount )
+        return min_amount;
+    }
+
+    return result;
+  }
+
+
+  /* brightness and contrast adjustment on the bitmap */
+  static FT_Bool
+  _ft_bitmap_bc  ( FT_Bitmap*       bitmap,
+                      float         brightness,
+                      float         contrast )
+  {
+
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  line    = bitmap->buffer;
+    FT_UInt   xx;
+
+
+    if ( brightness == 0 && contrast == 0 )
+      return FALSE;
+
+    for ( height = (FT_UInt)bitmap->rows;
+          height > 0;
+          height--, line += bitmap->pitch )
+    {
+      for ( xx = 0; xx < width - 1; xx += 1 )
+      {
+        if ( line[xx] > 0)
+        {
+          float  value  = (float)( 255 - line[xx] ) / 256.0;
+          FT_Int result = 0;
+
+          if ( brightness < 0.0 )
+            value = value * ( 1.0 + brightness );
+          else
+            value = value + ( ( 1.0 - value ) * brightness );
+
+          value = ( value - 0.5 ) *
+                    ( tan ( ( contrast + 1.0 ) * 3.141592/4.0 ) ) + 0.5;
+
+          result = (FT_Int)( 255.0 - value * 256.0 );
+
+          if ( result < 0 )
+            result = 0;
+          if ( result > 255 )
+            result = 255;
+
+          line[xx] = result;
+        }
+      }
+    }
+    return TRUE;
   }
 
 
-  /* This function writes every third byte in direct rendering mode */
+  /* Filter to mimic Windows-style sharpening */
+  /* Determined via 100% experimentation.     */
   static void
-  ft_smooth_lcd_spans( int             y,
-                       int             count,
-                       const FT_Span*  spans,
-                       TOrigin*        target )
+  _ft_lcd_windows_sharpen( FT_Bitmap*      bitmap,
+                           FT_Render_Mode  mode,
+                           FT_UInt         strength,
+                           FT_Library      library )
+  {
+
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  new_line;
+    FT_Byte*  line = bitmap->buffer;
+    FT_Bitmap new_bitmap;
+
+
+    FT_Bitmap_Init( &new_bitmap );
+    FT_Bitmap_Copy( library, bitmap, &new_bitmap );
+    new_line = (&new_bitmap)->buffer;
+
+    if (strength > 0)
+      for (height = (FT_UInt)bitmap->rows;
+           height > 0;
+           height--, line += bitmap->pitch, new_line += bitmap->pitch )
+    {
+      FT_UInt   xx, threshold = 128;
+      FT_Byte*  prevline      = line - bitmap->pitch;
+      FT_Byte*  nextline      = line + bitmap->pitch;
+      FT_Byte*  new_prevline  = new_line - bitmap->pitch;
+      FT_Byte*  new_nextline  = new_line + bitmap->pitch;
+
+      for ( xx = 1; xx < width - 1; xx += 1 )
   {
-    unsigned char*  dst_line = target->origin - y * target->pitch;
-    unsigned char*  dst;
-    unsigned short  w;
+        /* subpixel grid       sp11 sp21 sp31   */
+        /* where sp22 is       sp12 sp22 sp32   */
+        /* current subpixel.   sp13 sp23 sp33   */
+
+        FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff,
+          prevdiff, nextdiff, sp11, sp21, sp31, sp12, sp22, sp32,
+          sp13, sp23, sp33;
+
+        sp12 = line [xx-1];
+        sp22 = line [xx];
+        sp32 = line [xx+1];
 
+        if ( height == bitmap->rows )
+        {
+          prevtotal = sp11 = sp21 = sp31 = 0;
+          prevdiff = sp22;
+          lefttotal = sp12 + sp13;
+          righttotal = sp32 + sp33;
+        }
+        else
+        {
+          prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1];
+          sp11 = prevline [xx-1];
+          sp21 = prevline [xx];
+          sp31 = prevline [xx+1];
+          prevdiff = sp22 - sp21;
+          lefttotal = sp11 + sp12 + sp13;
+          righttotal = sp31 + sp32 + sp33;
+        }
 
-    for ( ; count--; spans++ )
-      for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 )
-        *dst = spans->coverage;
+        if ( height == 1 )
+        {
+          nexttotal = sp13 = sp23 = sp33 = 0;
+          nextdiff = sp22;
+          lefttotal = sp11 + sp12;
+          righttotal = sp31 + sp32;
+        }
+        else
+        {
+          nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1];
+          sp13 = nextline [xx-1];
+          sp23 = nextline [xx];
+          sp33 = nextline [xx+1];
+          nextdiff = sp23 - sp22;
+          lefttotal = sp11 + sp12 + sp13;
+          righttotal = sp31 + sp32 + sp33;
   }
 
+        sidesdiff = lefttotal - righttotal;
 
-  static FT_Error
-  ft_smooth_raster_lcd( FT_Renderer  render,
-                        FT_Outline*  outline,
-                        FT_Bitmap*   bitmap )
+        if ( sidesdiff < 0 )
+          sidesdiff *= -1;
+
+        if ( prevdiff < 0 )
+          prevdiff *= -1;
+
+        if ( nextdiff < 0 )
+          nextdiff *= -1;
+
+        /* if the current pixel is less than threshold, and greater than 0  */
+        if ( sp22 <= threshold && sp22 > 0 )
   {
-    FT_Error      error = FT_Err_Ok;
-    FT_Vector*    sub   = render->root.library->lcd_geometry;
-    FT_Pos        x, y;
+          /* A pixel is horizontally isolated if: */
+          /* 1: All upper adjecent pixels are >= threshold */
+          if ( prevtotal >= nexttotal  &&
+               abs( sp11 - sp12 ) > 5  &&
+               abs( sp21 - sp22 ) > 5  &&
+               abs( sp31 - sp32 ) > 5  && /* not a vert stem end */
+               sp11 >= threshold       &&
+               sp21 >= threshold       &&
+               sp31 >= threshold       &&
+               abs( sp23 - sp22 ) > 15 )  /* not on a vert stem */
+          {
+            /* darken upper adjacent subpixel;  lighten current */
+            if ( height != (FT_UInt)bitmap->rows )
+              new_prevline[xx] += ( ( 255 - new_prevline[xx] )
+                                      * strength ) / 100 ;
 
-    FT_Raster_Params   params;
-    TOrigin            target;
+            new_line[xx] -= ( new_line[xx] * strength ) / 100;
 
+            if ( height != 1 && height != (FT_UInt)bitmap->rows )
+              if ( new_nextline[xx] > 155 + ( 100 - strength ) )
+                new_prevline[xx] = 255;
 
-    /* Render 3 separate coverage bitmaps, shifting the outline.  */
-    /* Set up direct rendering to record them on each third byte. */
-    params.source     = outline;
-    params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
-    params.gray_spans = (FT_SpanFunc)ft_smooth_lcd_spans;
-    params.user       = &target;
-
-    params.clip_box.xMin = 0;
-    params.clip_box.yMin = 0;
-    params.clip_box.xMax = bitmap->width;
-    params.clip_box.yMax = bitmap->rows;
-
-    if ( bitmap->pitch < 0 )
-      target.origin = bitmap->buffer;
-    else
-      target.origin = bitmap->buffer
-                      + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
-
-    target.pitch = bitmap->pitch;
-
-    FT_Outline_Translate( outline,
-                          -sub[0].x,
-                          -sub[0].y );
-    error = render->raster_render( render->raster, &params );
-    x = sub[0].x;
-    y = sub[0].y;
-    if ( error )
-      goto Exit;
+          }
+          else if ( nexttotal > prevtotal  &&
+                    abs( sp13 - sp12 ) > 5  &&
+                    abs( sp23 - sp22 ) > 5  &&
+                    abs( sp33 - sp32 ) > 5  &&
+                    /* 2: All lower adjecent pixels are >= threshold */
+                    sp13 >= threshold      &&
+                    sp23 >= threshold      &&
+                    sp33 >= threshold      &&
+                    abs( sp22 - sp21 ) > 15 )
+          {
+            /* darken lower adjacent subpixel;  lighten current */
+            if ( height != 1 )
+              new_nextline[xx] += ( 255 - new_nextline[xx] ) * strength / 100;
 
-    target.origin++;
-    FT_Outline_Translate( outline,
-                          sub[0].x - sub[1].x,
-                          sub[0].y - sub[1].y );
-    error = render->raster_render( render->raster, &params );
-    x = sub[1].x;
-    y = sub[1].y;
-    if ( error )
-      goto Exit;
+            new_line[xx] -= ( new_line[xx] * strength ) / 100;
 
-    target.origin++;
-    FT_Outline_Translate( outline,
-                          sub[1].x - sub[2].x,
-                          sub[1].y - sub[2].y );
-    error = render->raster_render( render->raster, &params );
-    x = sub[2].x;
-    y = sub[2].y;
+            if ( height != 1 )
+              if ( new_nextline[xx] > 155 + ( 100 - strength ) )
+                new_nextline[xx] = 255;
 
-  Exit:
-    FT_Outline_Translate( outline, x, y );
+          }
+        }
+        else if ( sp22 > threshold && sp22 < 255 )
+        {
+          if ( sp11 <= threshold       &&
+               abs( sp13 - sp12 ) > 5  &&
+               abs( sp23 - sp22 ) > 5  &&
+               abs( sp33 - sp32 ) > 5  &&
+               sp21 <= threshold       &&
+               sp31 <= threshold       &&
+               prevtotal <= nexttotal  &&
+               abs( sp22 - sp21 ) > 15 )
+          {
+            /* bring this subpixel 1/3 of the way to 255 at 100% strength */
+            new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100;
 
-    return error;
+            if ( height != (FT_UInt)bitmap->rows )
+              new_prevline[xx] -= ( new_prevline[xx] * strength ) / 300;
   }
+          else if ( sp13 <= threshold       &&
+                    abs( sp11 - sp12 ) > 5  &&
+                    abs( sp21 - sp22 ) > 5  &&
+                    abs( sp31 - sp32 ) > 5  &&
+                    sp23 <= threshold       &&
+                    sp33 <= threshold       &&
+                    nexttotal < prevtotal   &&
+                    abs( sp23 - sp22 ) > 15 )
+          {
+            new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100;
 
+            if ( height != 1 )
+              new_nextline[xx] -= ( new_nextline[xx] * strength ) / 300;
+          }
+        }
+      }
+    }
+    FT_Bitmap_Copy( library, &new_bitmap, bitmap);
+    FT_Bitmap_Done( library, &new_bitmap );
+  }
 
-  static FT_Error
-  ft_smooth_raster_lcdv( FT_Renderer  render,
-                         FT_Outline*  outline,
-                         FT_Bitmap*   bitmap )
+
+  static void
+  _ft_lcd_darken_x  ( FT_Bitmap*      bitmap,
+                      FT_Render_Mode  mode,
+                      FT_UInt         strength,
+                      FT_Library      library )
   {
-    FT_Error     error = FT_Err_Ok;
-    int          pitch = bitmap->pitch;
-    FT_Vector*   sub   = render->root.library->lcd_geometry;
-    FT_Pos       x, y;
 
-    FT_Raster_Params  params;
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  new_line;
+    FT_Byte*  line = bitmap->buffer;
+    FT_Bitmap new_bitmap;
+    int       factor1, factor2;
+    int       bias = 0;
 
+    FT_Bitmap_Init( &new_bitmap );
 
-    params.target = bitmap;
-    params.source = outline;
-    params.flags  = FT_RASTER_FLAG_AA;
+    FT_Bitmap_Copy( library, bitmap, &new_bitmap );
+    new_line = (&new_bitmap)->buffer;
 
-    /* Render 3 separate coverage bitmaps, shifting the outline. */
-    /* Notice that the subpixel geometry vectors are rotated.    */
-    /* Triple the pitch to render on each third row.            */
-    bitmap->pitch *= 3;
-    bitmap->rows  /= 3;
-
-    FT_Outline_Translate( outline,
-                          -sub[0].y,
-                          sub[0].x );
-    error = render->raster_render( render->raster, &params );
-    x = sub[0].y;
-    y = -sub[0].x;
-    if ( error )
-      goto Exit;
+    if ( strength > 0 )
+      for ( height = (FT_UInt)bitmap->rows;
+            height > 0;
+            height--, line += bitmap->pitch, new_line += bitmap->pitch )
+    {
+      FT_UInt   xx;
+      FT_Byte*  prevline = line - bitmap->pitch;
+      FT_Byte*  nextline = line + bitmap->pitch;
 
-    bitmap->buffer += pitch;
-    FT_Outline_Translate( outline,
-                          sub[0].y - sub[1].y,
-                          sub[1].x - sub[0].x );
-    error = render->raster_render( render->raster, &params );
-    x = sub[1].y;
-    y = -sub[1].x;
-    bitmap->buffer -= pitch;
-    if ( error )
-      goto Exit;
+      for ( xx = 1; xx < width - 1; xx += 1 )
+      {
+        /* subpixel grid       sp11 sp21 sp31   */
+        /* where sp22 is       sp12 sp22 sp32   */
+        /* current subpixel.   sp13 sp23 sp33   */
 
-    bitmap->buffer += 2 * pitch;
-    FT_Outline_Translate( outline,
-                          sub[1].y - sub[2].y,
-                          sub[2].x - sub[1].x );
-    error = render->raster_render( render->raster, &params );
-    x = sub[2].y;
-    y = -sub[2].x;
-    bitmap->buffer -= 2 * pitch;
+        FT_Int sp21, sp12, sp22, sp32, sp23;
 
-  Exit:
-    FT_Outline_Translate( outline, x, y );
+        sp12 = line [xx-1];
+        sp22 = line [xx];
+        sp32 = line [xx+1];
 
-    bitmap->pitch /= 3;
-    bitmap->rows  *= 3;
+        if ( height == bitmap->rows )
+          sp21 = 0;
+        else
+          sp21 = prevline [xx];
+
+        if ( height == 1 )
+          sp23 = 0;
+        else
+          sp23 = nextline [xx];
+
+        /* darken subpixel if neighbor above and below are much less than */
+        /* safer but less effective */
+        factor1 = 5;
+        factor2 = 5;
+
+        /* make matches in the middle of glyph slightly darker */
+        /*if (height > 1 && height < (FT_UInt)bitmap->rows) bias = 1;*/
+
+        if ( sp22 > factor1 * sp21  &&
+             sp22  > factor1 * sp23 &&
+             sp22 > factor2         &&
+             sp12 > 16              &&
+             sp32 > 16              )
+          if ( new_line[xx] < ( strength * 255 ) / 100 )
+            new_line[xx] = (strength * 255 ) / 100
+                             + bias * ( 255 - ( strength * 255 ) / 100 ) / 3;
 
-    return error;
+      }
+    }
+    FT_Bitmap_Copy( library, &new_bitmap, bitmap );
+    FT_Bitmap_Done( library, &new_bitmap );
   }
 
-#else   /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
-  /* initialize renderer -- init its raster */
-  static FT_Error
-  ft_smooth_init( FT_Renderer  render )
+  static void
+  _ft_lcd_darken_y  ( FT_Bitmap*      bitmap,
+                      FT_Render_Mode  mode,
+                      FT_UInt         strength,
+                      FT_Library      library )
   {
-    /* set up default LCD filtering */
-    FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
 
-    render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  new_line;
+    FT_Byte*  line = bitmap->buffer;
+    FT_Bitmap   new_bitmap;
 
-    return 0;
+
+    FT_Bitmap_Init( &new_bitmap );
+    FT_Bitmap_Copy( library, bitmap, &new_bitmap );
+    new_line = (&new_bitmap)->buffer;
+
+    if ( strength > 0 )
+      for ( height = (FT_UInt)bitmap->rows;
+            height > 0;
+            height--, line += bitmap->pitch, new_line += bitmap->pitch )
+    {
+      FT_UInt  xx;
+
+
+      for ( xx = 1; xx < width - 1; xx += 1 )
+      {
+        if ( line[xx] > line[xx-1] && line[xx] > line[xx+1] )
+        {
+           if (new_line[xx] > 0)
+             new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100;
+           new_line[xx-1] += ( strength * ( 255 - line[xx-1] ) ) / 100;
+           new_line[xx+1] += ( strength * ( 255 - line[xx+1] ) ) / 100;
+        }
+      }
+    }
+    FT_Bitmap_Copy( library, &new_bitmap, bitmap );
+    FT_Bitmap_Done( library, &new_bitmap );
   }
 
 
-  static FT_Error
-  ft_smooth_raster_lcd( FT_Renderer  render,
-                        FT_Outline*  outline,
-                        FT_Bitmap*   bitmap )
+  static void
+  _ft_bitmap_cap  ( FT_Bitmap*      bitmap,
+                    FT_UInt         strength,
+                    FT_Library      library )
   {
-    FT_Error    error      = FT_Err_Ok;
-    FT_Vector*  points     = outline->points;
-    FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
-    FT_Vector*  vec;
 
-    FT_Raster_Params  params;
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  new_line;
+    FT_Byte*  line = bitmap->buffer;
+    FT_UInt   cur_value = 0;
+    FT_Bitmap new_bitmap;
 
 
-    params.target = bitmap;
-    params.source = outline;
-    params.flags  = FT_RASTER_FLAG_AA;
+    FT_Bitmap_Init( &new_bitmap );
+    FT_Bitmap_Copy( library, bitmap, &new_bitmap );
+    new_line = (&new_bitmap)->buffer;
 
-    /* implode outline */
-    for ( vec = points; vec < points_end; vec++ )
-      vec->x *= 3;
+    if ( strength > 0 )
+      for ( height = (FT_UInt)bitmap->rows;
+            height > 0;
+            height--, line += bitmap->pitch, new_line += bitmap->pitch )
+    {
+      FT_UInt  xx;
 
-    /* render outline into the bitmap */
-    error = render->raster_render( render->raster, &params );
 
-    /* deflate outline */
-    for ( vec = points; vec < points_end; vec++ )
-      vec->x /= 3;
+      for ( xx = 1; xx < width - 1; xx += 1 )
+      {
+        cur_value = ( new_line[xx-1] + new_line[xx] + new_line[xx+1] ) / 3;
+        if ( cur_value > ( strength * 255 ) / 100 )
+        {
+          FT_UInt new_factor = ( strength * 255 ) / 100;
+          new_line[xx] = ( new_line[xx] * new_factor ) / cur_value;
+          new_line[xx+1] = ( new_line[xx+1] * new_factor ) / cur_value;
+          new_line[xx-1] = ( new_line[xx-1] * new_factor ) / cur_value;
+        }
+      }
+    }
+    FT_Bitmap_Copy( library, &new_bitmap, bitmap );
+    FT_Bitmap_Done( library, &new_bitmap );
+  }
 
-    return error;
+  static int
+  pseudo_gamma ( int val, float value )
+  {
+      return 256 * ( 1.0f - powf( ( 1.0f - val * (1.0f/256.0f) ), 1.0f / value ) );
   }
 
+#if(0)
+  static void
+  _ft_bitmap_embolden  ( FT_Bitmap*      bitmap,
+                         FT_UInt         strength,
+                         FT_Library      library )
+  {
 
-  static FT_Error
-  ft_smooth_raster_lcdv( FT_Renderer  render,
-                         FT_Outline*  outline,
-                         FT_Bitmap*   bitmap )
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  new_line;
+    FT_Byte*  line = bitmap->buffer;
+    FT_Bitmap new_bitmap;
+    FT_UInt   xx;
+
+
+    FT_Bitmap_Init(&new_bitmap);
+    FT_Bitmap_Copy(library, bitmap, &new_bitmap);
+    new_line = (&new_bitmap)->buffer;
+
+    if ( strength > 0 )
+      for ( height = (FT_UInt)bitmap->rows;
+            height > 0;
+            height--, line += bitmap->pitch, new_line += bitmap->pitch )
   {
-    FT_Error    error      = FT_Err_Ok;
-    FT_Vector*  points     = outline->points;
-    FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
-    FT_Vector*  vec;
+      for ( xx = 1; xx < width - 1; xx += 1 )
+      {
+        FT_Int new_value = 0;
 
-    FT_Raster_Params  params;
 
+        new_value = ( strength * line [xx-1] ) / 100
+                      + pseudo_gamma( line [xx], .75 )
+                      + (strength * line [xx+1] ) / 100;
+        if ( new_value > 255 )
+          new_value = 255;
 
-    params.target = bitmap;
-    params.source = outline;
-    params.flags  = FT_RASTER_FLAG_AA;
+        new_line[xx] = new_value;
+      }
+    }
+    FT_Bitmap_Copy( library, &new_bitmap, bitmap );
+    FT_Bitmap_Done( library, &new_bitmap );
+  }
 
-    /* implode outline */
-    for ( vec = points; vec < points_end; vec++ )
-      vec->y *= 3;
 
-    /* render outline into the bitmap */
-    error = render->raster_render( render->raster, &params );
 
-    /* deflate outline */
-    for ( vec = points; vec < points_end; vec++ )
-      vec->y /= 3;
+  static void
+  _ft_bitmap_gamma  ( FT_Bitmap*    bitmap,
+                      float         strength )
+  {
 
-    return error;
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  line = bitmap->buffer;
+    FT_UInt   xx;
+
+
+    if ( strength > 0 )
+      for ( height = (FT_UInt)bitmap->rows;
+            height > 0;
+            height--, line += bitmap->pitch )
+    {
+
+      for ( xx = 1; xx < width - 1; xx += 1 )
+      {
+        if ( abs( line[xx-1] - line[xx] ) < 20 ||
+             abs( line[xx+1] - line[xx] ) < 20 )
+        line [xx] = pseudo_gamma( line [xx], strength ) ;
+      }
+    }
+  }
+#endif
+
+  /* Fringe filter */
+  static void
+  _ft_lcd_fringe_filter ( FT_Bitmap*      bitmap,
+                          FT_Render_Mode  mode,
+                          FT_UInt         strength,
+                          FT_Library      library )
+  {
+
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  new_line;
+    FT_Byte*  line = bitmap->buffer;
+    FT_Bitmap   new_bitmap;
+
+
+    FT_Bitmap_Init(&new_bitmap);
+
+    line = bitmap->buffer;
+    FT_Bitmap_Copy( library, bitmap, &new_bitmap );
+    new_line = (&new_bitmap)->buffer;
+
+    for ( height = (FT_UInt)bitmap->rows;
+          height > 0;
+          height--, line += bitmap->pitch, new_line += bitmap->pitch )
+    {
+      /* Threshold set to 1/2 pixel intensity */
+      FT_UInt  xx, threshold = 128;
+
+      /* Hack to make this work when bitmap is at first or last line */
+      FT_Int   fudge = bitmap->pitch * (height == (FT_UInt)bitmap->rows);
+
+      FT_Byte*  prevline = line - bitmap->pitch + fudge;
+      FT_Byte*  nextline = line + bitmap->pitch;
+
+
+      for ( xx = 1; xx < width - 1; xx += 1 )
+      {
+        /* subpixel grid       sp11 sp21 sp31   */
+        /* where sp22 is       sp12 sp22 sp32   */
+        /* current subpixel.   sp13 sp23 sp33   */
+
+        FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff,
+          leftdiff, rightdiff, prevdiff, nextdiff, sp11, sp21, sp31,
+          sp12, sp22, sp32, sp13, sp23, sp33;
+
+        sp12 = line [xx-1];
+        sp22 = line [xx];
+        sp32 = line [xx+1];
+
+        /* if at max height fake out some values */
+        if ( height == (FT_UInt)bitmap->rows )
+        {
+          prevtotal = sp11 = sp21 = sp31 = 0;
+          prevdiff = sp22;
+          lefttotal = sp12 + sp13;
+          righttotal = sp32 + sp33;
+        }
+        else
+        {
+          prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1];
+          sp11 = prevline [xx-1];
+          sp21 = prevline [xx];
+          sp31 = prevline [xx+1];
+          prevdiff = sp22 - sp21;
+          lefttotal = sp11 + sp12 + sp13;
+          righttotal = sp31 + sp32 + sp33;
+        }
+
+        /* if at min height fake out some values */
+        if ( height == 1 )
+        {
+          nexttotal = sp13 = sp23 = sp33 = 0;
+          nextdiff = sp22;
+          lefttotal = sp11 + sp12;
+          righttotal = sp31 + sp32;
+        }
+        else
+        {
+          nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1];
+          sp13 = nextline [xx-1];
+          sp23 = nextline [xx];
+          sp33 = nextline [xx+1];
+          nextdiff = sp23 - sp22;
+          lefttotal = sp11 + sp12 + sp13;
+          righttotal = sp31 + sp32 + sp33;
+        }
+
+        sidesdiff = lefttotal - righttotal;
+        leftdiff = sp22 - sp12;
+        rightdiff = sp32 - sp22;
+
+        if ( sidesdiff < 0 )
+          sidesdiff *= -1;
+
+        if ( prevdiff < 0 )
+          prevdiff *= -1;
+
+        if ( nextdiff < 0 )
+          nextdiff *= -1;
+
+        if ( leftdiff < 0 )
+          leftdiff *= -1;
+
+        if ( rightdiff < 0 )
+          rightdiff *= -1;
+
+        /* if the current subpixel is less than threshold, and varies only
+          slightly to left or right, lighten it */
+        if ( sp22 <= threshold && sp22 > 0       &&
+             ( leftdiff < 10 || rightdiff < 10 ) )
+        {
+          /* A pixel is horizontally isolated if: */
+          /* 1: All upper adjecent subpixels are >= threshold and all lower
+             adjacent ones are essentially white */
+          if ( prevtotal >= nexttotal &&
+               sp11 >= threshold      &&
+               sp21 >= threshold      &&
+               sp31 >= threshold      &&
+               sp13 < 2               &&
+               sp23 < 2               &&
+               sp33 < 2               )
+
+          {
+            new_line[xx] -= ( new_line[xx] * strength ) / 100;
+
+            if ( leftdiff < 10 )
+              /* OPPORTUNITY FOR IMPROVEMENT  - keep going left until 255? */
+              new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200;
+
+            if ( rightdiff < 10 )
+              /* OPPORTUNITY FOR IMPROVEMENT */
+              new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200;
+          }
+          else if ( nexttotal > prevtotal &&
+                    /* 2: the inverse of above */
+                    sp13 >= threshold     &&
+                    sp23 >= threshold     &&
+                    sp33 >= threshold     &&
+                    sp11 < 2              &&
+                    sp21 < 2              &&
+                    sp31 < 2              )
+          {
+            new_line[xx] -= ( new_line[xx] * strength ) / 100;
+
+            if ( leftdiff < 10 )
+              /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255?  */
+              new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200;
+
+            if ( rightdiff < 10 )
+              /* OPPORTUNITY FOR IMPROVEMENT */
+              new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200;
+          }
+        }
+        /* otherwise if the current subpixel is more than threshold, and varies
+          slightly to left or right, darken it */
+        else if ( sp22 > threshold    &&
+                  sp22 < 255          &&
+                  ( leftdiff < 10  ||
+                    rightdiff < 10 )  )
+        {
+          if ( sp11 <= 2             &&
+               sp21 <= 2             &&
+               sp31 <= 2             &&
+               sp13 >= threshold     &&
+               sp23 >= threshold     &&
+               sp33 >= threshold     &&
+               prevtotal < nexttotal )
+            new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100;
+
+          else if ( sp13 <= 2             &&
+                    sp23 <= 2             &&
+                    sp33 <= 2             &&
+                    nexttotal < prevtotal &&
+                    sp11 >= threshold     &&
+                    sp21 >= threshold     &&
+                    sp31 >= threshold     )
+            new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100;
+
+        }
   }
+    }
+    FT_Bitmap_Copy( library, &new_bitmap, bitmap );
+    FT_Bitmap_Done( library, &new_bitmap );
+  }
+
+
+  /* Grayscale filter */
+  static void
+  _ft_lcd_grayscale_filter ( FT_Bitmap*      bitmap,
+                             FT_Render_Mode  mode,
+                             FT_UInt         strength,
+                             FT_Library      library )
+  {
+
+    FT_UInt   width   = (FT_UInt)bitmap->width;
+    FT_UInt   height  = (FT_UInt)bitmap->rows;
+    FT_Byte*  line    = bitmap->buffer;
+
+
+    for ( height = (FT_UInt)bitmap->rows;
+          height > 0;
+          height--, line += bitmap->pitch )
+    {
+      FT_UInt xx;
 
-#endif  /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
-/* Oversampling scale to be used in rendering overlaps */
-#define SCALE  ( 1 << 2 )
+      for ( xx = 0; xx < width - 1; xx += 3 )
+      {
+        FT_UInt total = line [xx] + line [xx + 1] + line [xx + 2];
+        line[xx] =   ( ( 100 - strength ) * line[xx]
+                       + strength * ( total / 3 ) ) / 100;
+        line[xx+1] = ( ( 100 - strength ) * line[xx+1]
+                       + strength * ( total / 3 ) ) / 100;
+        line[xx+2] = ( ( 100 - strength ) * line[xx+2]
+                       + strength * ( total / 3 ) ) / 100;
+      }
+    }
+  }
+
+/*
+  These need to be in sync with params inside ftinf.c
+  (not ideal but perhaps better than making these public)
+ */
+#define STEM_WIDTH_2_PPEM 18
+#define MAX_PPEM 100
+
+  typedef struct  Stem_Segment_
+  {
+    FT_Long       x1;
+    FT_Long       x2;
+    FT_Int        y;
+  } Stem_Segment;
+
+  typedef struct  Stem_Center_
+  {
+    FT_Long       x;
+    FT_Long       y;
+    FT_Long       w;
+    FT_Long       x1;
+    FT_Long       x2;
+  } Stem_Center;
+
+  typedef struct  Stem_
+  {
+    FT_Long       center;
+    FT_Long       count;
+    FT_Long       rcount; /* used to count within a range in possible stems */
+    FT_Long       width;
+    FT_Long       height;
+    FT_Short      zone;  /* 1 2 or 3 */
+    FT_Bool       generated;
+  } Stem;
 
-  /* This function averages inflated spans in direct rendering mode */
   static void
-  ft_smooth_overlap_spans( int             y,
-                           int             count,
-                           const FT_Span*  spans,
-                           TOrigin*        target )
+  swap_stem ( Stem* s1, Stem* s2 )
   {
-    unsigned char*  dst = target->origin - ( y / SCALE ) * target->pitch;
-    unsigned short  x;
-    unsigned int    cover, sum;
+    Stem s;
+    s.center = s1->center;
+    s.count  = s1->count;
+    s.rcount = s1->rcount;
+    s.width  = s1->width;
+    s.zone   = s1->zone;
+    s.generated = s1->generated;
+
+    s1->center = s2->center;
+    s1->count  = s2->count;
+    s1->rcount = s2->rcount;
+    s1->width  = s2->width;
+    s1->zone   = s2->zone;
+    s1->generated = s2->generated;
+
+    s2->center = s.center;
+    s2->count  = s.count;
+    s2->rcount = s.rcount;
+    s2->width  = s.width;
+    s2->zone   = s.zone;
+    s2->generated = s.generated;
+  }
+
+  /* Stem alignment for bitmaps;  A hack with very nice results */
+  /* Ideally this could be implemented on the outline, prior to
+   * rasterization.  Possible future enhancement is to use the
+   * warper code to achieve this */
+  static void
+  _lcd_stem_align ( FT_Bitmap*      bitmap,
+                    FT_Render_Mode  mode,
+                    FT_GlyphSlot    slot,
+                    FT_Long*        translate_value,
+                    float*          scale_value,
+                    FT_UInt         alignment_strength,
+                    FT_UInt         fitting_strength,
+                    float*          embolden_value
+                  )
+  {
+    FT_UInt         width   = (FT_UInt)bitmap->width;
+    FT_UInt         height  = (FT_UInt)bitmap->rows;
+
+    Stem_Segment*   segments;
+    Stem_Segment*   leftmost_segment;
+    Stem_Segment*   rightmost_segment;
+    Stem_Segment*   leftmost_segment_not_extrema;
+    Stem_Segment*   rightmost_segment_not_extrema;
+    Stem*           stems;
+    Stem*           possible_stems;
+    Stem*           leftmost_stem;
+    Stem*           rightmost_stem;
+    Stem_Data*      known_stem_values;
+    Stem_Center*    centers;
+    FT_Long         leftmost_point = width * 256;
+    FT_Long         rightmost_point = 0;
+    FT_Long         leftmost_point_not_extrema = width * 256;
+    FT_Long         rightmost_point_not_extrema = 0;
+    FT_Long         num_segments = 0;
+    FT_Long         num_centers = 0;
+    FT_Long         *stem_centers;
+    FT_UInt         h;
+    FT_ULong        valid_stems = 0, valid_possible_stems = 0;
+    FT_Long         center, stem_matches, stem_matches_ledge;
+    FT_Long         stem_matches_redge, next_center, last_matching_center;
+    FT_Long         last_matching_ledge, last_matching_redge, this_center;
+    FT_Int          max_strength;
+    FT_Byte*        line = bitmap->buffer;
+    FT_UInt         current_value = 0;
+    FT_UInt         xx;
+    FT_Long         linearHoriAdvance = slot->linearHoriAdvance >> 10;
+
+    FT_Int          m_horiBearingX = slot->metrics.horiBearingX;
+    FT_Int          m_horiAdvance = slot->metrics.horiAdvance;
+    FT_Int          m_width = slot->metrics.width;
+    FT_Pos          one_pixel = 768;
+    FT_Pos          one_third_pixel = 256;
+    FT_Int          columns_per_pixel = 3;
+    /*FT_Int          extra_columns = 6;*/
+
+    /* on / off flags for testing different features */
+    FT_Bool         strategy_translate_using_closest_stem = TRUE;
+    FT_Bool         strategy_scale_to_closest_centers = FALSE;
+    FT_Bool         strategy_scale_to_closest_centers_up_only = FALSE;
+    FT_Bool         strategy_always_use_distance_ceiling = FALSE;
+    FT_Bool         strategy_auto_change_center_offset = TRUE;
+    FT_Bool         strategy_use_m_control = FALSE;
+    FT_Bool         strategy_correct_out_of_bounds_outlines = FALSE;
+    FT_Bool         strategy_also_use_edge_detection_for_stems = FALSE;
+    FT_Bool         strategy_use_strengths = TRUE;
+    FT_Bool         strategy_synthesize_stems = FALSE;
+    FT_Bool         strategy_bearing_correction = TRUE;
+    FT_Bool         strategy_use_d_correction = TRUE;
+    FT_Bool         strategy_fit_to_width = FALSE;
+    /*FT_Bool         strategy_center_glyph = FALSE;*/
+
+    const FT_Int    MIN_PPEM = 7;
+    /*const FT_Int    MAX_PPEM = 100;*/
+    const FT_Int    MAX_STEMS = 3;
+    FT_Int          ppem = 0;
+
+    Stem_Data       stem_data;
+
+    /* reset to default */
+    *scale_value = 1.0;
+
+    /* Simply return in odd cases where these don't seem to be set */
+    /* Flash and some pdf viewers will crash otherwise */
+    if ( !slot->face                       ||
+         !slot->face->size                 ||
+         !slot->face->size->metrics.x_ppem )
+      return;
+
+    if ( slot->face->size->metrics.x_ppem > MAX_PPEM )
+      return;
+
+    if ( slot->face->size->metrics.x_ppem < MIN_PPEM )
+      return;
+
+    if ( !FT_IS_SCALABLE( slot->face ) )
+      return;
+
+    ppem = slot->face->size->metrics.x_ppem;
+
+    if ( ppem < 9 )
+      return;
+    if ( ppem > 20 )
+        strategy_use_m_control = TRUE;
+
+    /* only perform alignment on styles we know, that aren't bold or italic */
+    /* perhaps detection could be added on those that are not set? */
+    /* Require certain ppems for narrow and light fonts */
+    if( slot->face->style_name )
+    {
+      if ( strcasestr( slot->face->style_name, "Italic" )            ||
+           strcasestr( slot->face->style_name, "Oblique" )           ||
+           strcasestr( slot->face->style_name, "Script" )            ||
+           strcasestr( slot->face->style_name, "Handwriting" )       ||
+           strcasestr( slot->face->style_name, "Bold" )              ||
+           strcasestr( slot->face->style_name, "Black" )             ||
+           ( ( strcasestr( slot->face->style_name, "Extra Thin" )  ||
+               strcasestr( slot->face->style_name, "Extra Light" ) ) &&
+             ppem < 10 )                                             ||
+           ( strcasestr( slot->face->style_name, "Thin" )
+               && ppem < 10 )                                        ||
+           ( strcasestr( slot->face->style_name, "Light" )
+               && ppem < 10 )                                        ||
+           ( strcasestr( slot->face->style_name, "Narrow" )
+               && ppem < 15 )                                        ||
+           ( strcasestr( slot->face->style_name, "Condensed" )
+               && ppem < 20 )                                        )
+            return;
+    }
+
+    if( slot->face->family_name )
+    {
+      if ( strcasestr( slot->face->family_name, "Italic" )            ||
+           strcasestr( slot->face->family_name, "Oblique" )           ||
+           strcasestr( slot->face->family_name, "Script" )            ||
+           strcasestr( slot->face->family_name, "Handwriting" )       ||
+           strcasestr( slot->face->family_name, "Bold" )              ||
+           strcasestr( slot->face->family_name, "Black" )             ||
+           ( ( strcasestr( slot->face->family_name, "Extra Thin" )  ||
+               strcasestr( slot->face->family_name, "Extra Light" ) ) &&
+             ppem < 10 )                                              ||
+           ( strcasestr( slot->face->family_name, "Thin" )
+               && ppem < 10 )                                         ||
+           ( strcasestr( slot->face->family_name, "Light" )
+               && ppem < 10 )                                         ||
+           ( strcasestr( slot->face->family_name, "Narrow" )
+               && ppem < 15 )                                         ||
+           ( strcasestr( slot->face->family_name, "Condensed" )
+               && ppem < 20 )                                         )
+            return;
+    }
+    else if ( slot->face->style_flags )
+    {
+      if ( slot->face->style_flags & FT_STYLE_FLAG_ITALIC ||
+           slot->face->style_flags & FT_STYLE_FLAG_BOLD   ||
+           FT_IS_TRICKY( slot->face )                     )
+        return;
+    }
+    else return;
+
+    if ( mode != FT_RENDER_MODE_LCD )
+    {
+      columns_per_pixel = 1;
+      one_pixel = 256;
+      one_third_pixel = 85;
+      /*extra_columns = 0;*/
+      /* until this can be figured out just return */
+      /* There are issues with missing glyphs */
+      return;
+    }
+
+    known_stem_values=&stem_data;
+    if ( ftinf && ftinf->use_known_settings_on_selected_fonts )
+    {
+      ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, TRUE );
+      /* translate value may be set for < 10 */
+      if (known_stem_values->stem_translating_only > -1024 )
+      {
+          *translate_value = known_stem_values->stem_translating_only;
+          return;
+      }
+      if( known_stem_values->bearing_correction == FALSE )
+          strategy_bearing_correction = FALSE;
+    } else
+        ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, FALSE );
+
+    if ( known_stem_values->use_100 ||
+         known_stem_values->m >= 0  )
+    {
+      alignment_strength = fitting_strength = 100;
+      strategy_use_m_control = TRUE;
+    }
+
+    if ( known_stem_values->edge_detection )
+      strategy_also_use_edge_detection_for_stems = TRUE;
+
+    /* Allocate */
+    segments = NULL;
+    leftmost_segment = (Stem_Segment*) malloc( 4*sizeof ( Stem_Segment ) );
+    leftmost_segment_not_extrema = leftmost_segment+1;
+    rightmost_segment = leftmost_segment+2;
+    rightmost_segment_not_extrema = leftmost_segment+3;
+
+    stems          = (Stem*) malloc ( (2*MAX_STEMS+2) * sizeof ( Stem ) );
+    possible_stems = stems+MAX_STEMS;
+    leftmost_stem  = possible_stems+MAX_STEMS;
+    rightmost_stem = leftmost_stem + 1;
+    centers        = NULL;
+
+    if ( verbose )
+      printf("\n");
+
+    /* Initialize */
+    stem_centers=(FT_Long*)calloc( width * 256, sizeof(stem_centers[0]) );
+
+    rightmost_segment->x1 = 0;
+    rightmost_segment->x2 = 0;
+    rightmost_segment->y  = 0;
+    leftmost_segment->x1  = 99999999;
+    leftmost_segment->x2  = 0;
+    leftmost_segment->y   = 0;
+
+    rightmost_segment_not_extrema->x1 = 0;
+    rightmost_segment_not_extrema->x2 = 0;
+    rightmost_segment_not_extrema->y  = 0;
+    leftmost_segment_not_extrema->x1  = 99999999;
+    leftmost_segment_not_extrema->x2  = 0;
+    leftmost_segment_not_extrema->y   = 0;
+
+    /* Locate stem centers for later processing */
+    for ( h = (FT_UInt)bitmap->rows; h > 0; h--, line += bitmap->pitch )
+    {
+      current_value = 0;
+      /* Calculate various sums and stem widths of glyph */
+      for ( xx = 0; xx < width; xx += 1 )
+      {
+        /* Reallocate (in blocks of 64) */
+        if( num_segments % 64 == 0 )
+            segments = (Stem_Segment*) realloc
+                ( segments, ( num_segments + 64 ) * sizeof ( Stem_Segment ) );
+
+        /* if line is white, and now has color, it's the start of a stem */
+        if ( current_value == 0 && line[xx] > 0 )
+        {
+          /* start of stem */
+          segments[num_segments].x1 = 256 * xx + ( 255 - line[xx] );
+          segments[num_segments].y = h;
+        }
+
+        /* otherwise, if it's currently black and the new value is 0,
+           it's the end of a stem */
+        else if ( ( current_value > 0 && line[xx] == 0 )   ||
+                  ( current_value > 0 && xx == width - 1 ) )
+        {
+          FT_Long stem_center_x;
+          segments[num_segments].x2 = 256 * ( xx - 1 ) + line[xx-1];
+
+          if ( xx == width - 1 )
+            segments[num_segments].x2 += line[xx];
+
+          /*stem center is average of start and end of stem */
+          stem_center_x = ( segments[num_segments].x2
+                            + segments[num_segments].x1 ) / 2;
+
+          /* Reallocate (in blocks of 32) */
+          if( num_centers % 32 == 0 )
+              centers = (Stem_Center*) realloc
+                  ( centers, ( num_centers + 32 ) * sizeof ( Stem_Center ) );
+          centers[num_centers].x = stem_center_x;
+          centers[num_centers].y = h;
+          centers[num_centers].x1 = segments[num_segments].x1;
+          centers[num_centers].x2 = segments[num_segments].x2;
+
+          num_centers++;
+
+          stem_centers[stem_center_x] += 1;
+
+          /* Find left and rightmost points for later calculations */
+          /* OR - Favor ones that aren't on the top or bottom if   */
+          /* possible to prevent v and w from getting caught later */
+          if ( segments[num_segments].x1 < leftmost_segment->x1      ||
+               ( segments[num_segments].y > 1                      &&
+                 segments[num_segments].y < height                 &&
+                 segments[num_segments].x1 == leftmost_segment->x1 ) )
+          {
+            leftmost_segment->x1 = segments[num_segments].x1;
+            leftmost_segment->x2 = segments[num_segments].x2;
+            leftmost_segment->y = h;
+          }
+          if ( segments[num_segments].x2 > rightmost_segment->x2      ||
+               ( segments[num_segments].y > 1                       &&
+                 segments[num_segments].y < height                  &&
+                 segments[num_segments].x1 == rightmost_segment->x1 ) )
+          {
+            rightmost_segment->x1 = segments[num_segments].x1;
+            rightmost_segment->x2 = segments[num_segments].x2;
+            rightmost_segment->y = h;
+          }
+
+          if ( segments[num_segments].x1
+                 < leftmost_segment_not_extrema->x1      ||
+               ( segments[num_segments].y > 1          &&
+                 segments[num_segments].y < height     &&
+                 segments[num_segments].x1
+                   == leftmost_segment_not_extrema->x1 &&
+                 h < (FT_UInt)bitmap->rows && h > 0    ) )
+          {
+            leftmost_segment_not_extrema->x1 = segments[num_segments].x1;
+            leftmost_segment_not_extrema->x2 = segments[num_segments].x2;
+            leftmost_segment_not_extrema->y = h;
+          }
+          if ( segments[num_segments].x2
+                 > rightmost_segment_not_extrema->x2      ||
+               ( segments[num_segments].y > 1           &&
+                 segments[num_segments].y < height      &&
+                 segments[num_segments].x1
+                   == rightmost_segment_not_extrema->x1 &&
+                 h < (FT_UInt)bitmap->rows && h > 0     ) )
+          {
+            rightmost_segment_not_extrema->x1 = segments[num_segments].x1;
+            rightmost_segment_not_extrema->x2 = segments[num_segments].x2;
+            rightmost_segment_not_extrema->y = h;
+          }
+
+          if ( segments[num_segments].x1 < leftmost_point )
+            leftmost_point = segments[num_segments].x1;
+
+          if ( segments[num_segments].x2 > rightmost_point )
+            rightmost_point = segments[num_segments].x2;
+
+          if ( segments[num_segments].x1 < leftmost_point_not_extrema &&
+               h < (FT_UInt)bitmap->rows && h > 0                     )
+            leftmost_point_not_extrema = segments[num_segments].x1;
+
+          if ( segments[num_segments].x2 > rightmost_point_not_extrema &&
+               h < (FT_UInt)bitmap->rows && h > 0                      )
+            rightmost_point_not_extrema = segments[num_segments].x2;
+
+          num_segments++;
+        }
+        /* else - other conditions - need some error checking here */
+        current_value = line[xx];
+      }
+    }
+
+    /* initialize */
+    for ( xx = 0; xx < MAX_STEMS; xx +=1 )
+    {
+      stems[xx].center = 0;
+      stems[xx].count = 0;
+      stems[xx].width = 0;
+      stems[xx].height = 0;
+      possible_stems[xx].center = 0;
+      possible_stems[xx].count = 0;
+      possible_stems[xx].width = 0;
+      possible_stems[xx].height = 0;
+    }
+
+    valid_stems = 0;
+    valid_possible_stems = 0;
+
+    /* Determine which centers belong to stems */
+    center = 0;
+
+    while ( center < num_centers )
+    {
+      /* slope at within which to consider a point part of a stem */
+      /*const FT_UInt slope = 1;
+      const FT_UInt topslope = (256 * 3) / 10; */
+
+      /* 10 to 20 with 4 matches seems good,                   */
+      /* but 1 or 2 with 3 stems needs to somehow get included */
+      FT_Int deviation1 = 5;
+      FT_Int deviation2=-1, requirement1 = 4, stem_match_requirement = 3;
+      FT_Int center_difference_in_height;
+      FT_Int center_difference_in_width, valid_center_average;
+      FT_Int smallest_width_ledge, smallest_width_redge;
+      FT_Int x1_difference_in_width, x2_difference_in_width;
+      FT_Bool no_gap_found = FALSE;
+      FT_Bool no_gap_found_ledge = FALSE;
+      FT_Bool no_gap_found_redge = FALSE;
+      FT_Bool stem_detected = FALSE;
+      FT_Int set_width_to, set_center_to;
+
+      /* seems to not do damage */
+      /* May not be effective */
+      requirement1 = height / 4;
+      if ( requirement1 < 5 )
+        requirement1 = 5;
+      deviation1 = 20;
+      deviation2 = 20;
+
+      if ( columns_per_pixel == 1 )
+        deviation1 = deviation2 = 10;
+
+      if ( (FT_Int)bitmap->rows <= 6 )
+        deviation1 = 25;
+
+      if ( (FT_Int)bitmap->rows <= 6 )
+        deviation2 = 25;
+
+      if ( columns_per_pixel == 1    &&
+           (FT_Int)bitmap->rows <= 6 )
+        deviation1 = deviation2 = 12;
+
+      valid_center_average = 0;
+
+      no_gap_found = no_gap_found_ledge = no_gap_found_redge = FALSE;
+      stem_detected = FALSE;
+
+      if ( ppem < 11 )
+        requirement1 = 4;
+
+      if ( ppem > 18 )
+      {
+        stem_match_requirement = height / 4;
+        if ( stem_match_requirement < 3 )
+          stem_match_requirement = 3;
+      }
+
+      smallest_width_ledge = smallest_width_redge = width * 256;
+      stem_matches = 0;
+      stem_matches_ledge = 0;
+      stem_matches_redge = 0;
+      last_matching_center = -1;
+      last_matching_ledge = -1;
+      last_matching_redge = -1;
+
+      /* set currently looked at center to center value */
+      this_center = center;
+      next_center = 0;
+
+      /* For each center, compare with all other centers to see if others */
+      /* match the properties of this one                                 */
+      while ( next_center < num_centers )
+      {
+
+        /* calculate differences */
+        center_difference_in_width = abs ( centers[this_center].x
+                                             - centers[next_center].x );
+        center_difference_in_height = abs ( centers[this_center].y
+                                              - centers[next_center].y );
+        x1_difference_in_width = abs ( centers[this_center].x1
+                                         - centers[next_center].x1 );
+        x2_difference_in_width = abs ( centers[this_center].x2
+                                         - centers[next_center].x2 );
+
+
+        /* property - stem center points that align                        */
+        /* if the center is within range, the center is less than          */
+        /* 1/2 the height away, and at least one edge is also within range */
+        if ( center_difference_in_width
+               < center_difference_in_height * deviation1     &&
+             center_difference_in_height
+               <= (FT_Int)bitmap->rows / 2                    &&
+             /* prevents w from getting caught ---- but also kills m */
+             ( x1_difference_in_width
+                 < center_difference_in_height * deviation2 ||
+               x2_difference_in_width
+                 < center_difference_in_height * deviation2 ) )
+        {
+          stem_matches += 1;
+          valid_center_average += centers[next_center].x;
+
+          /* try to find where the matching centers are far apart */
+          if ( last_matching_center >= 0 &&
+               abs( centers[last_matching_center].y
+                      - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 )
+
+          /* try to find where matching centers are next to each other */
+          if ( last_matching_center >= 0 &&
+               abs( centers[last_matching_center].y
+                      - centers[next_center].y ) == 1 )
+            no_gap_found = TRUE;
+
+          last_matching_center = next_center;
+        }
+
+        if ( strategy_also_use_edge_detection_for_stems )
+        {
+          /* property - stem left edge points that align */
+          /* if the center is within range,              */
+          /* the center is less than 1/2 the height away */
+          if ( x1_difference_in_width
+                 < center_difference_in_height * deviation1            &&
+               center_difference_in_height <= (FT_Int)bitmap->rows / 2 )
+          {
+            stem_matches_ledge += 1;
+            /* may not need for edges */
+            /*valid_center_average += centers[next_center].x;  */
+
+            if ( centers[next_center].x2 - centers[next_center].x1
+                   < smallest_width_ledge )
+              smallest_width_ledge = centers[next_center].x2
+                                       - centers[next_center].x1;
+
+            /* try to find where the matching centers are far apart */
+            if ( last_matching_ledge >= 0            &&
+                 abs( centers[last_matching_ledge].y
+                        - centers[next_center].y)
+                   >= (FT_Int)bitmap->rows / 2       )
+
+            /* try to find where matching centers are next to each other */
+            if ( last_matching_ledge >= 0               &&
+                 abs( centers[last_matching_ledge].y
+                        - centers[next_center].y ) == 1 )
+              no_gap_found_ledge = TRUE;
+            last_matching_ledge = next_center;
+          }
+        }
+
+        if ( strategy_also_use_edge_detection_for_stems )
+        {
+          /* property - stem right edge points that align               */
+          /* if the center is within range, the center is less than 1/2 */
+          /* the height away                                            */
+          if ( x2_difference_in_width
+                 < center_difference_in_height * deviation1 &&
+               center_difference_in_height
+                 <= (FT_Int)bitmap->rows / 2                )
+          {
+            stem_matches_redge += 1;
+            /* may not need for edges */
+            /*valid_center_average += centers[next_center].x; */
+
+            if ( centers[next_center].x2 - centers[next_center].x1
+                   < smallest_width_redge )
+              smallest_width_redge = centers[next_center].x2
+                                       - centers[next_center].x1;
+
+            /* try to find where the matching centers are far apart */
+            if ( last_matching_redge >= 0 &&
+                 abs( centers[last_matching_redge].y
+                       - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 )
+
+            /* try to find where matching centers are next to each other */
+            if ( last_matching_redge >= 0 &&
+                 abs( centers[last_matching_redge].y
+                        - centers[next_center].y ) == 1 )
+              no_gap_found_redge = TRUE;
+
+            last_matching_redge = next_center;
+          }
+        }
+
+        next_center++;
+      }
+
+      if ( stem_matches > 0 )
+        valid_center_average /= stem_matches;
+
+      if ( ( stem_matches >= stem_match_requirement             ||
+             ( ( (FT_Int)bitmap->rows <= 6 || ppem < 11 )   &&
+                 stem_matches >= 2                          &&
+                 abs ( valid_center_average
+                       - centers[center].x) < deviation1 /2 ) ||
+            /* try to catch tightly aligned stuff where the matching centers */
+            /* are next to each other only                                   */
+             ( stem_matches == 2                            &&
+                 abs( valid_center_average
+                      - centers[center].x) <= deviation1 /2 &&
+                 no_gap_found                               &&
+                 ppem < 18 )                                    )     &&
+            /* catches things like times 16 u but gets a lot of w's too */
+            /* stem width is less than 1/3 of the bitmap width,         */
+            /* or bitmap_width is small                                 */
+            ( centers[center].x2 - centers[center].x1
+                   < (m_horiAdvance * 12) / 2                       ||
+                m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) )
+      {
+        stem_detected = TRUE;
+        set_width_to  = centers[center].x2 - centers[center].x1;
+        set_center_to = centers[center].x;
+      }
+
+      /* see if edges found anything */
+      if ( strategy_also_use_edge_detection_for_stems && !stem_detected )
+      {
+        /* Require no gap for edges */
+        /* stem width less than 1/3 bitmap width, or bitmap_width is small */
+        /* The stem occurs on the left side of glyph only */
+        if ( ( stem_matches_ledge >= stem_match_requirement &&
+               no_gap_found_ledge                           )        &&
+             ( centers[center].x2 - centers[center].x1
+                 < ( m_horiAdvance * 12 ) / 2 ||
+               m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) &&
+             centers[center].x < ( m_horiAdvance * 12 ) / 2          )
+        {
+          stem_detected = TRUE;
+          set_width_to  = smallest_width_ledge;
+          set_center_to = centers[center].x1 + set_width_to / 2;
+          stem_matches  = stem_matches_ledge;
+        }
+        /* Require no gap for edges                                           */
+        /* stem width is less than 1/3 bitmap width, or bitmap_width is small */
+        /* The stem occurs on the right side of glyph only                    */
+        else if ( ( stem_matches_redge >= stem_match_requirement  &&
+                    no_gap_found_redge                            )       &&
+                  ( centers[center].x2 - centers[center].x1
+                      < ( m_horiAdvance * 12 ) / 2 ||
+                    m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) &&
+                  centers[center].x > (m_horiAdvance * 12) / 2            )
+        {
+          stem_detected = TRUE;
+          set_width_to  = smallest_width_redge;
+          set_center_to = centers[center].x2 - set_width_to / 2;
+          stem_matches  = stem_matches_redge;
+        }
+      }
+
+
+      /*store and/or replace highest occurrences with 3 or more centers */
+      /* because this matched, it will become the top dog regardless */
+      if ( stem_detected && (stem_matches > possible_stems[0].height) )
+      {
+        /* if this is the first stem just go ahead */
+        if ( valid_possible_stems == 0 )
+        {
+          valid_possible_stems = 1;
+          possible_stems[0].center = set_center_to;
+          possible_stems[0].count  = stem_matches;
+          possible_stems[0].width  = set_width_to;
+          possible_stems[0].height = stem_matches;
+        }
+
+        /* otherwise, if there is already a stem */
+        else if ( valid_possible_stems == 1 )
+        {
+          /* if stem is within range of existing one, replace existing one */
+
+          /* if the stem isn't within the range of this one swap it with   */
+          /* next one first                                                */
+          if ( abs ( set_center_to - possible_stems[0].center )
+                 >= one_pixel * 2 )
+          {
+            swap_stem ( &possible_stems[0], &possible_stems[1] );
+            valid_possible_stems = 2;
+          }
+          possible_stems[0].center = set_center_to;
+          possible_stems[0].count  = stem_matches;
+          possible_stems[0].width  = set_width_to;
+          possible_stems[0].height = stem_matches;
+        }
+
+        /* otherwise if there are already 2 stems */
+        else if ( valid_possible_stems >= 2 )
+        {
+          /* if the stem is within the range of existing one, replace     */
+          /* existing one                                                 */
+          if ( abs ( set_center_to - possible_stems[0].center )
+                 <= one_pixel * 2 )
+          {
+            possible_stems[0].center = set_center_to;
+            possible_stems[0].count  = stem_matches;
+            possible_stems[0].width  = set_width_to;
+            possible_stems[0].height = stem_matches;
+          }
+          /* if the stem isn't within the range of this one */
+          else
+          {
+            /* see if within range of next one and swap if so and proceed */
+            /* overwriting it                                             */
+            if ( abs ( set_center_to - possible_stems[1].center )
+                   <= one_pixel * 2 )
+              swap_stem ( &possible_stems[0], &possible_stems[1] );
+
+            /* otherwise see if in range of third one */
+            else if ( abs ( set_center_to - possible_stems[2].center )
+                        <= one_pixel * 2 )
+              swap_stem ( &possible_stems[0], &possible_stems[2] );
+
+            /* otherwise this is the new top dog, so demote everything */
+            else
+            {
+              swap_stem ( &possible_stems[1], &possible_stems[2] );
+              swap_stem ( &possible_stems[0], &possible_stems[1] );
+              valid_possible_stems += 1;
+            }
+            possible_stems[0].center = set_center_to;
+            possible_stems[0].count  = stem_matches;
+            possible_stems[0].width  = set_width_to;
+            possible_stems[0].height = stem_matches;
+          }
+        }
+      }
 
+      else if ( stem_matches > possible_stems[1].height &&
+                set_center_to != 0                      )
+      {
 
-    /* When accumulating the oversampled spans we need to assure that  */
-    /* fully covered pixels are equal to 255 and do not overflow.      */
-    /* It is important that the SCALE is a power of 2, each subpixel   */
-    /* cover can also reach a power of 2 after rounding, and the total */
-    /* is clamped to 255 when it adds up to 256.                       */
-    for ( ; count--; spans++ )
+        /* make sure it doesn't match the first stem */
+        if ( abs ( set_center_to - possible_stems[0].center ) >= one_pixel * 2 )
     {
-      cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE );
-      for ( x = 0; x < spans->len; x++ )
+
+          /* if this is the second stem */
+          if ( valid_possible_stems == 1 )
+            valid_possible_stems = 2;
+
+          /* otherwise if there is already a stem here */
+          else if ( valid_possible_stems >= 2 )
+          {
+            /* if it doesn't match the second stem, proceed to swap out    */
+            /* with the third.  if it does, replace it                     */
+            if ( abs ( set_center_to - possible_stems[1].center )
+                   >= one_pixel * 2 )
       {
-        sum                           = dst[( spans->x + x ) / SCALE] + cover;
-        dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) );
+              swap_stem ( &possible_stems[1], &possible_stems[2] );
+              valid_possible_stems +=1;
       }
     }
+          possible_stems[1].center = set_center_to;
+          possible_stems[1].count  = stem_matches;
+          possible_stems[1].width  = set_width_to;
+          possible_stems[1].height = stem_matches;
+        }
   }
 
+      else if ( stem_matches > possible_stems[2].height &&
+                set_center_to != 0                      )
+      {
+        /* if it doesn't match the first or second one */
+        if ( abs( set_center_to - possible_stems[0].center) >= one_pixel * 2 &&
+             abs( set_center_to - possible_stems[1].center) >= one_pixel * 2 )
+        {
+          if ( valid_possible_stems == 2 )
+            valid_possible_stems += 1;
 
-  static FT_Error
-  ft_smooth_raster_overlap( FT_Renderer  render,
-                            FT_Outline*  outline,
-                            FT_Bitmap*   bitmap )
+          possible_stems[2].center = set_center_to;
+          possible_stems[2].count  = stem_matches;
+          possible_stems[2].width  = set_width_to;
+          possible_stems[1].height = stem_matches;
+        }
+      }
+
+      if ( valid_possible_stems > 3 )
+        valid_possible_stems = 3;
+
+      center++;
+    }
+
+    /* promote to stem */
+    if ( valid_possible_stems > 0 )
   {
-    FT_Error    error      = FT_Err_Ok;
-    FT_Vector*  points     = outline->points;
-    FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
-    FT_Vector*  vec;
+      stems[0].center    = possible_stems[0].center;
+      stems[0].count     = possible_stems[0].count;
+      stems[0].width     = possible_stems[0].width;
+      stems[0].height    = possible_stems[0].height;
+      stems[0].generated = FALSE;
+      valid_stems++;
+    }
 
-    FT_Raster_Params   params;
-    TOrigin            target;
+    if ( valid_stems == 1         &&
+         valid_possible_stems > 1 )
+    {
+      stems[1].center    = possible_stems[1].center;
+      stems[1].count     = possible_stems[1].count;
+      stems[1].width     = possible_stems[1].width;
+      stems[1].height    = possible_stems[1].height;
+      stems[1].generated = FALSE;
+      valid_stems++;
+    }
 
+    if ( valid_stems == 2              &&
+         valid_possible_stems > 2      &&
+         possible_stems[2].center != 0 )
+    {
+      stems[2].center    = possible_stems[2].center;
+      stems[2].count     = possible_stems[2].count;
+      stems[2].width     = possible_stems[2].width;
+      stems[2].height    = possible_stems[2].height;
+      stems[2].generated = FALSE;
+      valid_stems++;
+    }
 
-    /* Reject outlines that are too wide for 16-bit FT_Span.       */
-    /* Other limits are applied upstream with the same error code. */
-    if ( bitmap->width * SCALE > 0x7FFF )
-      return FT_THROW( Raster_Overflow );
+    /* sort stems in x direction */
+    if ( valid_stems == 3 )
+    {
+      if ( stems[0].center > stems[1].center )
+        swap_stem ( &stems[0], &stems[1] );
 
-    /* Set up direct rendering to average oversampled spans. */
-    params.source     = outline;
-    params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
-    params.gray_spans = (FT_SpanFunc)ft_smooth_overlap_spans;
-    params.user       = &target;
+      if ( stems[0].center > stems[2].center )
+        swap_stem ( &stems[1], &stems[2] );
+
+      if ( stems[1].center > stems[2].center )
+        swap_stem ( &stems[1], &stems[2] );
+
+      if ( stems[0].center > stems[1].center )
+        swap_stem ( &stems[0], &stems[1] );
+
+      /* only look at first and last stem for now */
+      swap_stem ( &stems[1], &stems[2] );
+    }
+
+   /* synthesize stems - Works, but needs work */
+   if ( ( strategy_synthesize_stems      ||
+          known_stem_values->synth_stems ) &&
+          valid_stems  == 0                &&
+          ppem > 10                        )
+    {
+      /* if the leftmost segment's leftmost point is the same as the glyph's */
+      /* leftmost point, and it is of reasonable width, and is not on the    */
+      /* top or bottom of the bitmap                                         */
+      if ( leftmost_segment_not_extrema->x1
+             == leftmost_point_not_extrema             &&
+           abs ( leftmost_segment_not_extrema->x2
+                   - leftmost_segment_not_extrema->x1 )
+             < ( rightmost_point_not_extrema
+                   - leftmost_point_not_extrema ) / 3  &&
+           leftmost_segment_not_extrema->y < height    &&
+           leftmost_segment_not_extrema->y > 1         )
+      {
+        stems[valid_stems].center = ( leftmost_segment_not_extrema->x2
+                                        + leftmost_segment_not_extrema->x1 ) / 2;
+        stems[valid_stems].width = leftmost_segment_not_extrema->x2
+                                        - leftmost_segment_not_extrema->x1;
+        stems[valid_stems].generated = TRUE;
+        valid_stems += 1;
+      }
+
+
+      if ( rightmost_segment_not_extrema->x2
+             == rightmost_point_not_extrema             &&
+           abs ( rightmost_segment_not_extrema->x2
+                   - rightmost_segment_not_extrema->x1 )
+             < ( rightmost_point_not_extrema
+                   - leftmost_point_not_extrema ) / 3   &&
+           rightmost_segment_not_extrema->y < height    &&
+           rightmost_segment_not_extrema->y > 1         )
+      {
+        stems[valid_stems].center = ( rightmost_segment_not_extrema->x2
+                                      + rightmost_segment_not_extrema->x1 ) / 2;
+        stems[valid_stems].width = rightmost_segment_not_extrema->x2
+                                      - rightmost_segment_not_extrema->x1;
+        stems[valid_stems].generated = TRUE;
+        valid_stems += 1;
+      }
+
+    }
+
+    /* sort stems in x direction */
+    if ( valid_stems > 1 && stems[0].center > stems[1].center )
+      swap_stem ( &stems[0], &stems[1] );
+
+    if ( valid_stems == 0 && known_stem_values->stem_translating != 0 )
+    {
+      *translate_value += known_stem_values->stem_translating;
+
+      if ( strategy_use_strengths )
+      {
+        /* consider 1/2 pixel the max when strength is at 100%,
+           unless translate is already greater than that */
+        FT_Int strength_cutoff = 32;
+
+
+        if ( abs ( *translate_value ) > strength_cutoff)
+          strength_cutoff = *translate_value;
+
+        max_strength = ( strength_cutoff * alignment_strength ) / 100;
+
+        if ( *translate_value < -max_strength )
+          *translate_value = -max_strength;
+        else if  ( *translate_value > max_strength )
+          *translate_value = max_strength;
+      }
+    }
+    else
+    /* Start snapping */
+    {
+      FT_Int  center_offset;
+      FT_Int  modulus;
+      FT_Int  delta, delta2;
+      FT_Long stem_distance = 1, new_distance = 1;
+      FT_Int  distance_floor, distance_ceiling;
+      FT_Int  translate_value2 = 0;
+      FT_Int  main_stem = 0;
+      FT_Int  lbearing = m_horiBearingX * 12;
+      FT_Int  bitmap_stem_location = stems[0].center;
+      FT_Int  advance_stem_location = bitmap_stem_location
+                                        + lbearing - one_pixel;
+      FT_Int  advance_width = m_horiAdvance * 12;
+      FT_Int  original_advance_width = 12 * ( slot->linearHoriAdvance >> 10 );
+      FT_Int  glyph_width = rightmost_point - leftmost_point;
+      FT_Int  stem_width = stems[0].width;
+      FT_Int  advance_leftmost_location = leftmost_point
+                                            + lbearing - one_pixel;
+      FT_Int  advance_rightmost_location = rightmost_point
+                                             + lbearing - one_pixel;
+
+#define proposed_transformed_point(point) \
+  point * (float)(new_distance) / (float)(stem_distance) \
+  + *translate_value * 12 - ( stems[main_stem].center * (float)(new_distance) \
+  / (float)(stem_distance) - stems[main_stem].center)
+
+#define proposed_translated_point(point) point + *translate_value * 12
 
-    params.clip_box.xMin = 0;
-    params.clip_box.yMin = 0;
-    params.clip_box.xMax = bitmap->width * SCALE;
-    params.clip_box.yMax = bitmap->rows  * SCALE;
+      center_offset = one_pixel / 2;   /* half pixel */
+      modulus = one_pixel;            /* whole pixel */
 
-    if ( bitmap->pitch < 0 )
-      target.origin = bitmap->buffer;
+      /* Determine center_offset via known values */
+      if ( known_stem_values->stem_width >= 0 )
+      {
+        if ( known_stem_values->stem_width % 2 == 0 )
+          center_offset = 0;
     else
-      target.origin = bitmap->buffer
-                      + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
+          center_offset = one_pixel / 2;
+      }
+      /* otherwise do intelligent guessing, if set */
+      else if ( strategy_auto_change_center_offset &&
+                ppem >= STEM_WIDTH_2_PPEM          &&
+                stems[0].width < one_pixel * 1.45  )
+        center_offset = one_pixel / 2;
+      else if ( strategy_auto_change_center_offset &&
+                ppem >= STEM_WIDTH_2_PPEM          &&
+                stems[0].width >= one_pixel * 1.45 &&
+                stems[0].width < one_pixel * 2.6   )
+        center_offset = 0;
+      else if ( strategy_auto_change_center_offset &&
+                ppem >= STEM_WIDTH_2_PPEM          &&
+                stems[0].width >= one_pixel * 2.6  &&
+                stems[0].width < one_pixel * 3.6   )
+        center_offset = one_pixel / 2;
+      else if ( strategy_auto_change_center_offset &&
+                ppem >= STEM_WIDTH_2_PPEM          )
+        center_offset =
+          ( one_pixel
+             * ( ( ( (int)( stems[0].width + one_pixel / 2 ) )
+                             / one_pixel ) % 2 ) ) / 2;
+
+      /* Snap to closest translate and scale values by default */
+      if ( valid_stems >= 1 )
+      {
+        /* closest snapping point for stem 0 */
+        delta = ( stems[0].center  + center_offset ) % modulus;
+
+        if ( delta < modulus / 2 )
+          /* snap left */
+          *translate_value = -delta / ( columns_per_pixel * 4 );
+        else
+           /* snap right */
+          *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 );
+      }
 
-    target.pitch = bitmap->pitch;
+      if ( strategy_use_d_correction )
+      {
+        /* if the only stem is in the last 1/3 of glyph width, the advance */
+        /* is 6 pixels, the ppem 11, and doing so doesn't violate bitmap , */
+        /* boundaries force it to snap right                               */
+        if ( valid_stems == 1                                  &&
+             advance_stem_location > (advance_width * 2) / 3   &&
+             advance_width == 6 * one_pixel                    &&
+             rightmost_point + modulus - delta
+               <= ( width - (columns_per_pixel * 2) / 3) * 256 &&
+             ppem == 11                                        )
+          *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 );
+      }
 
-    /* inflate outline */
-    for ( vec = points; vec < points_end; vec++ )
+      if ( strategy_use_strengths )
     {
-      vec->x *= SCALE;
-      vec->y *= SCALE;
+        /* consider 1/2 pixel the max when strength is at 100%,
+           unless translate is already greater than that */
+        FT_Int strength_cutoff = 32;
+        if ( abs ( *translate_value ) > strength_cutoff )
+          strength_cutoff = *translate_value;
+
+        max_strength = ( strength_cutoff * alignment_strength ) / 100;
+
+        if ( *translate_value < -max_strength )
+          *translate_value = -max_strength;
+        else if  ( *translate_value > max_strength )
+          *translate_value = max_strength;
     }
 
-    /* render outline into the bitmap */
-    error = render->raster_render( render->raster, &params );
+      /* If 2 stems is detected, scale distance
+         between in order to land on pixels */
+      if ( valid_stems >= 2 )
+      {
+        stem_distance = abs ( stems[1].center - stems[0].center );
 
-    /* deflate outline */
-    for ( vec = points; vec < points_end; vec++ )
+        delta = stem_distance % modulus;
+        new_distance = stem_distance - delta;
+
+        distance_floor = stem_distance - delta;
+        distance_ceiling = stem_distance + ( modulus - delta );
+
+        if ( delta < modulus / 2 )
+          new_distance = distance_floor;
+        else
+          new_distance = distance_ceiling;
+
+        if ( columns_per_pixel == 3                                    &&
+             valid_stems == 3                                          &&
+             strategy_use_m_control                                    &&
+             ( width - 2 * columns_per_pixel ) > 6 * columns_per_pixel &&
+             ppem > 8                                                  &&
+             ( advance_stem_location - advance_leftmost_location )
+               < stems[main_stem].width * 2                            )
+        {
+          /* Possibly use 2 only when compatible widths is on? */
+          FT_Int mod_factor = 2;
+
+          if ( verbose )
+            printf ( "USING M CONTROL ");
+
+          distance_floor = stem_distance
+                             - stem_distance % ( modulus * mod_factor ) ;
+          distance_ceiling = distance_floor + modulus * mod_factor;
+
+          new_distance = distance_ceiling;
+
+          /* force certain ideal situations */
+          /* these 2 are mostly safe to do */
+          if ( distance_ceiling
+                 + one_pixel * columns_per_pixel == advance_width &&
+               stem_width < one_pixel * 1.25                      )
+            new_distance = distance_ceiling;
+          /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER
+             THAT NUDGE IS UP OR DOWN */
+          else if ( stem_distance + one_pixel * 2.6 >= advance_width &&
+            stem_width < one_pixel * 1.25                            )
+            new_distance = distance_ceiling;
+
+          if ( proposed_transformed_point ( leftmost_point )
+                 < one_third_pixel * 2                       ||
+               proposed_transformed_point ( rightmost_point )
+                 > ( width -2 ) * one_third_pixel            )
+            new_distance = distance_floor;
+
+          /* NEED TO IGNORE SERIF Ms HERE */
+          /* perhaps check bitmap boundaries instead??? */
+          if ( strategy_bearing_correction && new_distance == distance_ceiling )
+          {
+            /* Correct if bearings are made substantially worse
+               (more than 1/3 a pixel beyond advance) */
+            if ( proposed_transformed_point( advance_rightmost_location )
+                   > advance_width + one_third_pixel                     &&
+                 proposed_transformed_point( advance_rightmost_location )
+                   > advance_rightmost_location                          &&
+                -proposed_transformed_point( advance_leftmost_location )
+                   < advance_rightmost_location - advance_width          )
+              new_distance = distance_floor;
+          }
+
+          if ( known_stem_values->m >= 0 )
     {
-      vec->x /= SCALE;
-      vec->y /= SCALE;
+            if ( known_stem_values->m == 0 )
+              new_distance = distance_floor;
+            else
+              new_distance = distance_ceiling;
     }
 
-    return error;
+          if ( ( rightmost_point - leftmost_point) -
+                ( ( rightmost_point * *scale_value)
+                  - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 )
+          {
+            *scale_value = 1.0;
+            *translate_value = 0;
+            goto Exit;
+          }
+
+        }
+        else if ( columns_per_pixel == 1                                &&
+                  valid_stems == 3 &&
+                  strategy_use_m_control && valid_stems == 3            &&
+                  width >= 6 * columns_per_pixel                        &&
+                  ppem > 8                                              &&
+                  ( advance_stem_location - advance_leftmost_location )
+                    < stems[main_stem].width * 2                        )
+        {
+          /* Possibly use 2 only when compatible widths is on? */
+          FT_Int mod_factor = 2;
+
+          if ( verbose )
+            printf ("USING M CONTROL ");
+          distance_floor = stem_distance - stem_distance
+                                             % ( modulus * mod_factor) ;
+          distance_ceiling = distance_floor + modulus * mod_factor;
+
+          new_distance = distance_ceiling;
+
+          /* force certain ideal situations */
+          /* these 2 are mostly safe to do */
+          if ( distance_ceiling
+                 + one_pixel * columns_per_pixel == advance_width &&
+               stem_width < one_pixel * 1.25                      )
+            new_distance = distance_ceiling;
+          /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER
+            THAT NUDGE IS UP OR DOWN */
+          else if ( stem_distance + one_pixel * 2.6 >= advance_width &&
+                    stem_width < one_pixel * 1.25                    )
+            new_distance = distance_ceiling;
+
+          if ( proposed_transformed_point( leftmost_point ) < 0 ||
+               proposed_transformed_point( rightmost_point )
+                 > width * one_pixel - 2 * one_third_pixel      )
+            new_distance = distance_floor;
+
+          /* NEED TO IGNORE SERIF Ms HERE */
+          /* perhaps check bitmap boundaries instead??? */
+          if ( strategy_bearing_correction && new_distance == distance_ceiling )
+          {
+            /* Correct if bearings are made substantially worse
+               (more than 1/3 a pixel beyond advance) */
+            if ( proposed_transformed_point( advance_rightmost_location )
+                   > advance_width + one_third_pixel                      &&
+                proposed_transformed_point( advance_rightmost_location )
+                   > advance_rightmost_location                           &&
+                -proposed_transformed_point( advance_leftmost_location )
+                   < advance_rightmost_location - advance_width           )
+              new_distance = distance_floor;
+          }
+
+          if ( known_stem_values->m >= 0 )
+          {
+            if ( known_stem_values->m == 0 )
+              new_distance = distance_floor;
+            else
+              new_distance = distance_ceiling;
+          }
+
+
+          if ( ( rightmost_point - leftmost_point )
+                 - ( ( rightmost_point * *scale_value )
+                      - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 )
+          {
+            *scale_value = 1.0;
+            *translate_value = 0;
+            goto Exit;
+          }
+
+        }
+        else
+        {
+          if ( strategy_fit_to_width )
+            new_distance = advance_width - 3 * one_pixel;
+          else if ( known_stem_values->stem_scaling >= 0 )
+          {
+            if ( known_stem_values->stem_scaling > 0 )
+              new_distance = distance_ceiling;
+            else
+              new_distance = distance_floor;
+
+            /* enforce advance width boundaries */
+            /* TOO RESTRICTIVE ON SERIF FONTS */
+            if ( proposed_transformed_point( advance_rightmost_location )
+                   >= advance_width                                      ||
+                 proposed_transformed_point( advance_leftmost_location )
+                   <= 0                                                  )
+              new_distance = distance_floor;
+
+            /* enforce literal bitmap boundaries if no translate room */
+            if ( ( proposed_transformed_point(rightmost_point) >= width * 256
+                || proposed_transformed_point(leftmost_point ) <= one_pixel )
+              && new_distance + one_pixel * 3 > advance_width )
+              new_distance = distance_floor;
+
+          }
+          else if ( strategy_translate_using_closest_stem )
+          {
+            /* closest snapping point for stem 1 */
+            delta2 = ( stems[1].center  + center_offset ) % modulus;
+
+            if ( delta2 < modulus / 2 )
+              /* snap left */
+              translate_value2 = -delta2 / ( columns_per_pixel * 4 );
+            else
+               /* snap right */
+              translate_value2 = ( modulus - delta2 )
+                                     / ( columns_per_pixel * 4 );
+
+            if ( abs ( translate_value2 ) < abs ( *translate_value ) )
+            {
+              *translate_value = translate_value2;
+              main_stem = 1;
+            }
+
+          }
+          else if ( strategy_scale_to_closest_centers )
+          {
+            /* closest snapping point for stem 0 */
+            delta  = ( stems[0].center + center_offset ) % modulus;
+            delta2 = ( stems[1].center + center_offset ) % modulus;
+
+            if ( delta < modulus / 2 )
+              /* stretch left */
+              new_distance = delta + stem_distance;
+            else
+              /* stretch right */
+              new_distance = delta - modulus + stem_distance;
+
+            if ( delta2 < modulus / 2 )
+              new_distance -= delta2;  /* stretch left */
+            else
+              new_distance += modulus - delta2; /* stretch right */
+
+          }
+          else if ( strategy_scale_to_closest_centers_up_only )
+          {
+            FT_Int net_change = 0;
+
+            /* closest snapping point for stem 0 */
+            delta  = ( stems[0].center + center_offset ) % modulus;
+            delta2 = ( stems[1].center + center_offset ) % modulus;
+
+            if ( delta < modulus / 2 )
+              net_change = delta;  /* stretch left */
+            else
+              net_change = -( modulus - delta );      /* stretch right */
+
+            if ( delta2 < modulus / 2 )
+              net_change -= delta2;  /* stretch left */
+            else
+              net_change += modulus - delta2;      /* stretch right */
+
+            if ( net_change > 0                                              &&
+                 proposed_transformed_point( advance_rightmost_location )
+                   < advance_width                                           &&
+                 proposed_transformed_point( advance_leftmost_location ) > 0 )
+              new_distance = distance_ceiling;
+          }
+
+          else if ( strategy_always_use_distance_ceiling )
+          {
+            if ( proposed_transformed_point( advance_rightmost_location )
+                   < advance_width                                           &&
+                 proposed_transformed_point( advance_leftmost_location ) > 0 )
+            new_distance = distance_ceiling;
+          }
+        }
+
+        if ( strategy_use_strengths )
+        {
+          FT_Int strength_cutoff = center_offset;
+
+
+          delta2 = new_distance - stem_distance;
+
+          if ( abs ( delta2 ) > strength_cutoff )
+            strength_cutoff = delta2;
+
+          max_strength = ( strength_cutoff * fitting_strength ) / 100;
+
+          if ( delta2 < -max_strength )
+            new_distance = stem_distance - max_strength;
+          else if ( delta2 > max_strength )
+            new_distance = stem_distance + max_strength;
+        }
+
+        *scale_value = (float)( new_distance ) / (float)( stem_distance );
+        *translate_value = *translate_value
+           - ( (float)( stems[main_stem].center * (float)new_distance )
+                      / (float)stem_distance - stems[main_stem].center ) / 12;
+
+        if ( valid_stems == 2 )
+          *embolden_value = ( 64.0 / *scale_value - 64.0 );
+
+        if ( valid_stems == 3 )
+          *embolden_value = ( 64.0 / *scale_value - 64.0 ) / 1.5;
+      }
+
+      if ( verbose )
+        printf ( "%lu stems:", valid_stems );
+
+      if ( valid_stems == 1 && verbose )
+        printf ( "1 stem:    bitmapwidth:%d glyphwidth:%f glyph_width:%f center:%f bearing:%f advance:%f lhadvance:%f stemwidth:%f %d %d",
+                (width - 6) / columns_per_pixel,
+                (float)m_width / 64.0,
+                (float)glyph_width / (float)one_pixel,
+                (float)( (float)advance_stem_location ) / (float)one_pixel,
+                (float)m_horiBearingX / 64.0,
+                (float)m_horiAdvance / 64.0,
+                (float)linearHoriAdvance / 64.0,
+                (float)stems[0].width / (float)one_pixel,
+                advance_width, original_advance_width );
+      else if ( valid_stems >= 2 && verbose )
+        printf ( "%lu stems: bitmapwidth:%d center1:%f center2:%f difference:%f bearing:%f advance:%f advstemloc:%f ",
+                valid_stems,
+                (width - 6) / columns_per_pixel,
+                ( (float)advance_stem_location ) / (float)one_pixel,
+                ( (float)advance_stem_location
+                    + (float)abs ( stems[1].center
+                                     - stems[0].center) ) / (float)one_pixel,
+                ( (float)abs ( stems[1].center
+                                 - stems[0].center ) ) / (float)one_pixel,
+                (float)m_horiBearingX / 64.0,
+                (float)m_horiAdvance / 64.0,
+                (float)advance_stem_location / (float)one_pixel );
+
+      if ( strategy_bearing_correction )
+      {
+        /* Correct if negative bearings are made substantially worse */
+        /* (more than 1/3 a pixel)                                   */
+        if ( proposed_transformed_point( advance_rightmost_location )
+               > advance_width                                       &&
+             proposed_transformed_point( advance_rightmost_location )
+               > advance_rightmost_location                          &&
+             -proposed_transformed_point( advance_leftmost_location )
+               < advance_rightmost_location - advance_width          &&
+             *translate_value
+               > one_third_pixel / ( columns_per_pixel * 4 )         )
+        {
+          *translate_value -=64 ;
+          if ( verbose )
+            printf ( "TRANSLATING -64 " );
+        }
+      }
+      goto Exit;
+    }
+
+  Exit:
+
+#define transformed_point( point ) point * *scale_value + *translate_value * 12
+
+    if ( strategy_correct_out_of_bounds_outlines )
+    {
+      /* Correct if outside bitmap */
+      if ( transformed_point( rightmost_point )
+             >= width * 256 - 2 * one_third_pixel &&
+           transformed_point( leftmost_point )
+             > one_pixel + 2 * one_third_pixel    )
+        *translate_value -=64 ;
+      else if ( transformed_point( leftmost_point )
+                  <= one_pixel / 2                                &&
+                transformed_point( rightmost_point )
+                  <= width * 256 - ( one_pixel +  one_pixel / 2 ) )
+        *translate_value += 64;
+    }
+
+    STVALUES
+    free ( centers );
+    free ( segments );
+    free ( stem_centers );
+    free ( stems );
+    free ( leftmost_segment );
   }
 
-#undef SCALE
 
+  /* Gamma correction */
+  static void
+  _ft_lcd_gamma_correction_correction ( FT_Bitmap*      bitmap,
+                                        FT_Render_Mode  mode,
+                                        FT_GlyphSlot    slot,
+                                        float           gamma_correction_lt,
+                                        float           gamma_correction_value )
+  {
+    if ( gamma_correction_value != 1.0 )
+    {
+      FT_UInt   width  = (FT_UInt)bitmap->width;
+      FT_UInt   height = (FT_UInt)bitmap->rows;
+      FT_Byte*  line   = bitmap->buffer;
+      float     ppem   = (float)slot->face->size->metrics.x_ppem;
+
+
+      if ( !slot->face || !slot->face->size ) return;
+
+      if ( ppem >= 5 )
+        for ( height = (FT_UInt)bitmap->rows;
+              height > 0;
+              height--, line += bitmap->pitch )
+        {
+          FT_UInt  xx;
+
+
+          for ( xx = 0; xx < width; xx += 1 )
+          {
+            /*normal*/
+            /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value );*/
+
+            /* sloped */
+            /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5
+            * (1-gamma_correction_value)/(gamma_correction_lt -5)
+            + ((1-gamma_correction_value)/(gamma_correction_lt -5)) * ppem );*/
+
+            /* 1/3-sloped */
+            line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5
+            * ( ( 1 - gamma_correction_value )
+                / ( 3 * ( gamma_correction_lt -5 ) ) )
+            + ( ( 1 - gamma_correction_value )
+                / ( 3 * ( gamma_correction_lt -5) ) ) * ppem );
+          }
+        }
+    }
+  }
+
+#endif
+
+  /* convert a slot's glyph image into a bitmap */
   static FT_Error
-  ft_smooth_render( FT_Renderer       render,
+  ft_smooth_render_generic( FT_Renderer       render,
                     FT_GlyphSlot      slot,
                     FT_Render_Mode    mode,
-                    const FT_Vector*  origin )
+                            const FT_Vector*  origin,
+                            FT_Render_Mode    required_mode )
   {
-    FT_Error     error   = FT_Err_Ok;
-    FT_Outline*  outline = &slot->outline;
+    FT_Error     error;
+    FT_Outline*  outline = NULL;
+    FT_Outline*  outline_orig = NULL;
+    FT_BBox      cbox;
+    FT_Pos       width, height, pitch, ppem;
+#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    FT_Pos       height_org, width_org;
+#endif
     FT_Bitmap*   bitmap  = &slot->bitmap;
     FT_Memory    memory  = render->root.memory;
+    FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
+    FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
     FT_Pos       x_shift = 0;
     FT_Pos       y_shift = 0;
+    FT_Pos       x_left, y_top;
+
+    FT_Raster_Params  params;
+
+    FT_Bool  have_translated_origin = FALSE;
+    FT_Bool  have_outline_shifted   = FALSE;
+    FT_Bool  have_buffer            = FALSE;
+
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    FT_Matrix    scaleMat;
+    FT_Long      translate_value = 0;
+    float        scale_value = 1.0;
+    FT_Int       align_called = 0;
+
+
+    int          chromeos_style_sharpening_strength = 0;
+    int          alignment_strength = 0;
+    int          fitting_strength = 0;
+    int          fringe_filter_strength = 0;
+    int          grayscale_filter_strength = 0;
+
+    int          autohint_horizontal_stem_darken_strength = 0;
+    int          autohint_vertical_stem_darken_strength = 0;
+
+    int          windows_style_sharpening_strength = 0;
+    float        gamma_correction_value = 1;
+    float        gamma_correction_lt = 0;
+
+    FT_Int       brightness_value = 0.0;
+    FT_Int       contrast_value = 0.0;
+
+    FT_Int       snapping_sliding_scale_value = 0;
+
+    FT_Int       global_embolden_x_value = 0;
+    FT_Int       global_embolden_y_value = 0;
+
+    FT_Int       bold_embolden_x_value = 0;
+    FT_Int       bold_embolden_y_value = 0;
+
+    FT_Byte      chromeos_cutoff;
+    double       chromeos_gamma_value;
+
+    float        embolden_value = 0.0;
+    FT_Bool      autohinted = FALSE;
+    FT_Bool      use_various_tweaks = FALSE;
+    FT_Pos       cur_width = infinality_cur_width;
+
+    const FT_Int MIN_PPEM = 1;
+    /*const FT_Int    MAX_PPEM = 100;    */
+
+    FT_Bool use_known_settings_on_selected_fonts;
+
+    if ( slot->face                       &&
+         slot->face->size                 &&
+         slot->face->size->metrics.x_ppem )
+      ppem = slot->face->size->metrics.x_ppem;
+    else
+      ppem = 0;
+
+    if ( cur_width )
+    {
+        autohinted = TRUE;
+    }
+    if( ftinf ){
+        const float *f=ftinf->gamma_correction;
+
+        use_known_settings_on_selected_fonts=ftinf->use_known_settings_on_selected_fonts;
+        use_various_tweaks=ftinf->use_various_tweaks;
+        snapping_sliding_scale_value=ftinf->stem_snapping_sliding_scale;
+
+        alignment_strength=ftinf->stem_alignment_strength;
+        if ( snapping_sliding_scale_value != 0 )
+            alignment_strength = sliding_scale(10, snapping_sliding_scale_value, alignment_strength, 100, ppem);
+
+        fitting_strength=ftinf->stem_fitting_strength;
+        if ( snapping_sliding_scale_value != 0 )
+            fitting_strength = sliding_scale(10, snapping_sliding_scale_value, fitting_strength, 100, ppem);
+
+        chromeos_style_sharpening_strength=ftinf->chromeos_style_sharpening_strength;
+
+        if ( ppem > 10 )
+            chromeos_style_sharpening_strength =
+                ( chromeos_style_sharpening_strength * ppem ) / 10;
+
+        if ( chromeos_style_sharpening_strength > 100 )
+            chromeos_style_sharpening_strength = 100;
+
+        brightness_value=ftinf->brightness;
+        contrast_value=ftinf->contrast;
+
+        windows_style_sharpening_strength=ftinf->windows_style_sharpening_strength;
+
+        /* Decrease effect slightly to have a more linear increase in sharpness */
+        windows_style_sharpening_strength =
+            ( ( windows_style_sharpening_strength
+                * windows_style_sharpening_strength ) / 100
+              + windows_style_sharpening_strength ) / 2;
 
+        gamma_correction_lt = f[0];
+        gamma_correction_value = f[1] / 100.0f;
+
+        fringe_filter_strength=ftinf->fringe_filter_strength;
+        grayscale_filter_strength=ftinf->grayscale_filter_strength;
+
+        autohint_horizontal_stem_darken_strength=ftinf->autohint_horizontal_stem_darken_strength;
+        autohint_vertical_stem_darken_strength=ftinf->autohint_vertical_stem_darken_strength;
+
+        global_embolden_x_value=ftinf->global_embolden_x_value;
+        global_embolden_y_value=ftinf->global_embolden_y_value;
+
+        bold_embolden_x_value=ftinf->bold_embolden_x_value;
+        bold_embolden_y_value=ftinf->bold_embolden_y_value;
+    } else {
+        use_known_settings_on_selected_fonts=FALSE;
+    }
+
+    /* set gamma value to 1 if out of range */
+    if ( slot->face                       &&
+         slot->face->size                 &&
+         slot->face->size->metrics.x_ppem )
+    {
+      if ( slot->face->size->metrics.x_ppem >= gamma_correction_lt )
+        gamma_correction_value = 1;
+    }
+    else
+      gamma_correction_value = 1;
+
+    if( use_various_tweaks     &&
+        slot->face             &&
+        slot->face->style_name )
+    {
+      /* needs to also check for artifical italics */
+      if ( strcasestr(slot->face->style_name, "Italic" )  ||
+           strcasestr(slot->face->style_name, "Oblique" ) )
+      {
+        windows_style_sharpening_strength = 0;
+        chromeos_style_sharpening_strength = 0;
+      }
+    }
+
+    /*if (fitting_strength == 100) scale_value = 1.1;*/
+
+#endif
+
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+
+    FT_Int                   lcd_extra          = 0;
+    FT_LcdFiveTapFilter      lcd_weights        = { 0 };
+    FT_Bool                  have_custom_weight = FALSE;
+    FT_Bitmap_LcdFilterFunc  lcd_filter_func    = NULL;
+
+
+    if ( slot->face )
+    {
+      FT_Char  i;
+
+
+      for ( i = 0; i < FT_LCD_FILTER_FIVE_TAPS; i++ )
+        if ( slot->face->internal->lcd_weights[i] != 0 )
+        {
+          have_custom_weight = TRUE;
+          break;
+        }
+    }
+
+    /*
+     * The LCD filter can be set library-wide and per-face.  Face overrides
+     * library.  If the face filter weights are all zero (the default), it
+     * means that the library default should be used.
+     */
+    if ( have_custom_weight )
+    {
+      /*
+       * A per-font filter is set.  It always uses the default 5-tap
+       * in-place FIR filter that needs 2 extra pixels.
+       */
+      ft_memcpy( lcd_weights,
+                 slot->face->internal->lcd_weights,
+                 FT_LCD_FILTER_FIVE_TAPS );
+      lcd_filter_func = ft_lcd_filter_fir;
+      lcd_extra       = 2;
+    }
+    else
+    {
+      /*
+       * The face's lcd_weights is {0, 0, 0, 0, 0}, meaning `use library
+       * default'.  If the library is set to use no LCD filtering
+       * (lcd_filter_func == NULL), `lcd_filter_func' here is also set to
+       * NULL and the tests further below pass over the filtering process.
+       */
+      ft_memcpy( lcd_weights,
+                 slot->library->lcd_weights,
+                 FT_LCD_FILTER_FIVE_TAPS );
+      lcd_filter_func = slot->library->lcd_filter_func;
+      lcd_extra       = slot->library->lcd_extra;
+    }
+
+#endif /*FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
     /* check glyph image format */
     if ( slot->format != render->glyph_format )
@@ -446,15 +2541,134 @@
     }
 
     /* check mode */
-    if ( mode != FT_RENDER_MODE_NORMAL &&
-         mode != FT_RENDER_MODE_LIGHT  &&
-         mode != FT_RENDER_MODE_LCD    &&
-         mode != FT_RENDER_MODE_LCD_V  )
+    if ( mode != required_mode )
     {
       error = FT_THROW( Cannot_Render_Glyph );
       goto Exit;
     }
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+RERENDER:
+    if ( align_called == 1 )
+    {
+      scaleMat.xx = FT_FixedFromFloat(scale_value);
+      scaleMat.xy = 0;
+      scaleMat.yx = 0;
+      scaleMat.yy = ( 1 << 16 );
+
+      FT_Outline_Copy(outline_orig, outline);
+
+      if ( scale_value != 1.0 )
+        FT_Outline_Transform( outline, &scaleMat );
+
+      FT_Outline_Translate( outline, translate_value, 0 );
+
+      FT_Outline_EmboldenXY( outline, embolden_value, 0 );
+    }
+    else
+    {
+#endif
+    outline = &slot->outline;
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+      /* Need to get this PRIOR to embolden, otherwise bad things happen */
+      FT_Outline_Get_CBox( outline, &cbox );
+
+      /* Various hacks that need to be turned into a new rule set */
+      /*if ( !autohinted
+        && use_known_settings_on_selected_fonts
+        && mode == FT_RENDER_MODE_LCD
+        && slot->face->family_name
+        && slot->face->style_name
+        && ( strcasestr(slot->face->family_name, "Courier New" )
+          && ( strcasestr(slot->face->style_name, "Regular" )
+            || strcasestr(slot->face->style_name, "Italic" ) ) ) )
+        FT_Outline_Embolden( outline, 24 );*/
+
+      if ( slot->face )
+      {
+        if ( !autohinted                                              &&
+            use_known_settings_on_selected_fonts                     &&
+            mode == FT_RENDER_MODE_LCD                               &&
+            slot->face->family_name                                  &&
+            slot->face->style_name                                   &&
+            strcasestr( slot->face->family_name, "Times New Roman" ) &&
+            strcasestr( slot->face->style_name, "Italic" )           )
+          FT_Outline_EmboldenXY( outline, 12, 0 );
+
+        if ( use_known_settings_on_selected_fonts              &&
+            autohinted                                        &&
+            mode == FT_RENDER_MODE_LCD                        &&
+            slot->face->family_name                           &&
+            slot->face->style_name                            &&
+            strcasestr(slot->face->family_name, "FreeSerif" ) &&
+            strcasestr(slot->face->style_name, "Italic" )     )
+          FT_Outline_EmboldenXY( outline, 8, 0 );
+
+        if ( global_embolden_x_value != 0 || global_embolden_y_value != 0 )
+              FT_Outline_EmboldenXY( outline,
+                                    global_embolden_x_value,
+                                    global_embolden_y_value );
+
+        if ( ( bold_embolden_x_value != 0 || bold_embolden_y_value != 0 ) &&
+            ( slot->face->style_name                             &&
+            ( strcasestr(slot->face->style_name, "Bold" ) ||
+              strcasestr(slot->face->style_name, "Black"  )    ||
+              ( slot->face->style_flags                      &&
+                slot->face->style_flags & FT_STYLE_FLAG_BOLD ) ) )       )
+          FT_Outline_EmboldenXY( outline,
+                                  bold_embolden_x_value,
+                                  bold_embolden_y_value );
+      }
+
+      FT_Outline_Copy( outline, outline_orig );
+    }
+
+    /* translate the outline to the new origin if needed */
+    if ( align_called == 0 )
+    {
+      FT_Pos enlarge_cbox = 0;
+
+      /* enlarge for grayscale rendering */
+      if ( mode == FT_RENDER_MODE_NORMAL )
+        enlarge_cbox = 64;
+
+      if ( origin )
+      {
+        FT_Outline_Translate( outline, origin->x, origin->y );
+        have_translated_origin = TRUE;
+      }
+
+      /* compute the control box, and grid fit it */
+      /*FT_Outline_Get_CBox( outline, &cbox );*/
+
+      cbox.xMin = FT_PIX_FLOOR( cbox.xMin - enlarge_cbox );
+      cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
+      cbox.xMax = FT_PIX_CEIL( cbox.xMax + enlarge_cbox );
+      cbox.yMax = FT_PIX_CEIL( cbox.yMax );
+#else
+    if ( origin )
+    {
+      FT_Outline_Translate( outline, origin->x, origin->y );
+      have_translated_origin = TRUE;
+    }
+
+    /* compute the control box, and grid fit it */
+    FT_Outline_Get_CBox( outline, &cbox );
+
+    cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
+    cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
+    cbox.xMax = FT_PIX_CEIL( cbox.xMax );
+    cbox.yMax = FT_PIX_CEIL( cbox.yMax );
+#endif
+
+    width  = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6;
+    height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6;
+
+#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    width_org  = width;
+    height_org = height;
+#endif
+
     /* release old bitmap buffer */
     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
     {
@@ -462,109 +2676,427 @@
       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
     }
 
-    if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
+    /* allocate new one */
+    pitch = width;
+    if ( hmul )
     {
-      error = FT_THROW( Raster_Overflow );
-      goto Exit;
+      width = width * 3;
+      pitch = FT_PAD_CEIL( width, 4 );
     }
 
-    if ( !bitmap->rows || !bitmap->pitch )
-      goto Exit;
+    if ( vmul )
+      height *= 3;
 
-    /* allocate new one */
-    if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
-      goto Exit;
+    x_shift = cbox.xMin;
+    y_shift = cbox.yMin;
+    x_left  = cbox.xMin >> 6;
+    y_top   = cbox.yMax >> 6;
 
-    slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    if ( lcd_filter_func )
+    {
+      if ( hmul )
+      {
+        x_shift -= 64 * ( lcd_extra >> 1 );
+        x_left  -= lcd_extra >> 1;
+        width   += 3 * lcd_extra;
+        pitch    = FT_PAD_CEIL( width, 4 );
+      }
 
-    x_shift = 64 * -slot->bitmap_left;
-    y_shift = 64 * -slot->bitmap_top;
-    if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
-      y_shift += 64 * (FT_Int)bitmap->rows / 3;
-    else
-      y_shift += 64 * (FT_Int)bitmap->rows;
+      if ( vmul )
+      {
+        y_shift -= 64 * ( lcd_extra >> 1 );
+        y_top   += lcd_extra >> 1;
+        height  += 3 * lcd_extra;
+      }
+    }
+#endif
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    }
+#endif
 
-    if ( origin )
+
+    /* Required check is (pitch * height < FT_ULONG_MAX),        */
+    /* but we care realistic cases only.  Always pitch <= width. */
+    if ( width > 0x7FFF || height > 0x7FFF )
     {
-      x_shift += origin->x;
-      y_shift += origin->y;
+      FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n",
+                 width, height ));
+      error = FT_THROW( Raster_Overflow );
+      goto Exit;
     }
 
-    /* translate outline to render it into the bitmap */
-    if ( x_shift || y_shift )
-      FT_Outline_Translate( outline, x_shift, y_shift );
+    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+    bitmap->num_grays  = 256;
+    bitmap->width      = (unsigned int)width;
+    bitmap->rows       = (unsigned int)height;
+    bitmap->pitch      = pitch;
 
-    if ( mode == FT_RENDER_MODE_NORMAL ||
-         mode == FT_RENDER_MODE_LIGHT  )
+    /* translate outline to render it into the bitmap */
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    if ( align_called == 0 )
     {
-      if ( outline->flags & FT_OUTLINE_OVERLAP )
-        error = ft_smooth_raster_overlap( render, outline, bitmap );
-      else
+#endif
+    FT_Outline_Translate( outline, -x_shift, -y_shift );
+    have_outline_shifted = TRUE;
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    }
+#endif
+    /* release old bitmap buffer */
+    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
       {
-        FT_Raster_Params  params;
+      FT_FREE( bitmap->buffer );
+      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
+    }
 
+    if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) )
+      goto Exit;
+    else
+      have_buffer = TRUE;
 
+    slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+
+    /* set up parameters */
         params.target = bitmap;
         params.source = outline;
         params.flags  = FT_RASTER_FLAG_AA;
 
-        error = render->raster_render( render->raster, &params );
-      }
-    }
-    else
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+
+    /* implode outline if needed */
     {
-      if ( mode == FT_RENDER_MODE_LCD )
-        error = ft_smooth_raster_lcd ( render, outline, bitmap );
-      else if ( mode == FT_RENDER_MODE_LCD_V )
-        error = ft_smooth_raster_lcdv( render, outline, bitmap );
+      FT_Vector*  points     = outline->points;
+      FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
+      FT_Vector*  vec;
 
-#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 
-      /* finally apply filtering */
+      if ( hmul )
+        for ( vec = points; vec < points_end; vec++ )
+          vec->x *= 3;
+
+      if ( vmul )
+        for ( vec = points; vec < points_end; vec++ )
+          vec->y *= 3;
+    }
+
+    /* render outline into the bitmap */
+    error = render->raster_render( render->raster, &params );
+
+    /* deflate outline if needed */
       {
-        FT_Byte*                 lcd_weights;
-        FT_Bitmap_LcdFilterFunc  lcd_filter_func;
+      FT_Vector*  points     = outline->points;
+      FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
+      FT_Vector*  vec;
+
+
+      if ( hmul )
+        for ( vec = points; vec < points_end; vec++ )
+          vec->x /= 3;
+
+      if ( vmul )
+        for ( vec = points; vec < points_end; vec++ )
+          vec->y /= 3;
+    }
+
+    if ( error )
+      goto Exit;
 
+#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET
+    if ( ppem <= MAX_PPEM && ppem >= MIN_PPEM )
+    {
+      if ( align_called == 0                                  &&  cur_width / ppem < 10 &&
+           ( alignment_strength > 0 || fitting_strength > 0 ) )
+        _lcd_stem_align ( bitmap,
+                          mode,
+                          slot,
+                          &translate_value,
+                          &scale_value,
+                          alignment_strength,
+                          fitting_strength,
+                          &embolden_value );
 
-        /* Per-face LCD filtering takes priority if set up. */
-        if ( slot->face && slot->face->internal->lcd_filter_func )
+      if ( align_called == 0                              &&
+           ( translate_value != 0 || scale_value != 1.0 ) )
         {
-          lcd_weights     = slot->face->internal->lcd_weights;
-          lcd_filter_func = slot->face->internal->lcd_filter_func;
+        align_called = 1;
+        goto RERENDER;
         }
-        else
+
+      if ( mode == FT_RENDER_MODE_LCD )
         {
-          lcd_weights     = slot->library->lcd_weights;
-          lcd_filter_func = slot->library->lcd_filter_func;
+
+        if ( fringe_filter_strength > 0 /*&& autohinted*/ )
+          _ft_lcd_fringe_filter( bitmap,
+                                 mode,
+                                 fringe_filter_strength,
+                                 slot->library );
+
+        /*if ( autohinted)
+          _ft_lcd_stem_end_filter( bitmap, mode, 100, slot->library );*/
+
+        if ( gamma_correction_lt > 0 && gamma_correction_value != 1.0 )
+          _ft_lcd_gamma_correction_correction( bitmap,
+                                               mode,
+                                               slot,
+                                               gamma_correction_lt,
+                                               gamma_correction_value );
+
+        chromeos_cutoff = (FT_Byte)( 0.5 * 255.0 )
+                            * ( chromeos_style_sharpening_strength / 100.0 );
+        chromeos_gamma_value = 1;
+
+        if ( chromeos_style_sharpening_strength > 0 )
+          _ft_lcd_chromeos_sharpen( bitmap,
+                                    mode,
+                                    chromeos_cutoff,
+                                    chromeos_gamma_value );
+
+        if ( ppem > 8 )
+          if ( windows_style_sharpening_strength > 0 )
+            _ft_lcd_windows_sharpen( bitmap,
+                                     mode,
+                                     windows_style_sharpening_strength,
+                                     slot->library );
+
+        if ( autohinted                                    &&
+             ( cur_width * 100 ) / 64
+               > autohint_horizontal_stem_darken_strength  &&
+             autohint_horizontal_stem_darken_strength != 0 )
+          autohint_horizontal_stem_darken_strength = ( cur_width * 100 ) / 64;
+
+        if ( autohint_horizontal_stem_darken_strength > 100)
+          autohint_horizontal_stem_darken_strength = 100;
+
+        /* only do on autohinted fonts */
+        /* Necessary to do on some non-thin fonts, which is why it is outside */
+        /* of the below conditional */
+        if ( autohint_horizontal_stem_darken_strength > 0 && autohinted )
+          _ft_lcd_darken_x ( bitmap,
+                             mode,
+                             autohint_horizontal_stem_darken_strength,
+                             slot->library );
+
+        /* Enhance thin fonts */
+        if ( autohinted )
+        {
+          /* if forcibly set use that, otherwise make a good estimate */
+          float contrast, brightness;
+          ftinf_get_bc( slot->face->family_name, ppem, &brightness, &contrast);
+          if ( slot->face && !_ft_bitmap_bc ( bitmap, brightness, contrast ) )
+          {
+            FT_Bool is_fixed_name = FALSE;
+
+            if ( slot->face->family_name                      &&
+                 strcasestr(slot->face->family_name, "Mono" ) )
+              is_fixed_name = TRUE;
+
+            /* Darken vertical stems */
+            _ft_lcd_darken_y ( bitmap,
+                               mode,
+                               autohint_vertical_stem_darken_strength,
+                               slot->library );
+
+            /* Adjust brightness / contrast automatically based on stem width */
+            if ( cur_width != 0 && cur_width < 30 )
+              cur_width = 30;
+
+            if ( cur_width >= 30 && cur_width <= 60 )
+            {
+              float ppem_factor       = sliding_scale ( 5, 11, 0.0, 1.0, ppem );
+              float brightness_factor = sliding_scale ( 30, 52, -.3, 0.0,
+                                                        cur_width );
+              float contrast_factor   = sliding_scale ( 30, 52, .45, 0.0,
+                                                        cur_width );
+              _ft_bitmap_bc ( bitmap,
+                              ppem_factor * brightness_factor,
+                              ppem_factor * contrast_factor );
+
+              /* Only cap variable width thin-stemmed fonts */
+              if ( !FT_IS_FIXED_WIDTH( slot->face ) && !is_fixed_name )
+                _ft_bitmap_cap ( bitmap,
+                                 ( cur_width * 150 ) / 64,
+                                 slot->library );
         }
+          }
+        }
+
 
         if ( lcd_filter_func )
-          lcd_filter_func( bitmap, lcd_weights );
+          lcd_filter_func( bitmap, mode, lcd_weights );
+
+        if ( grayscale_filter_strength > 0 )
+          _ft_lcd_grayscale_filter( bitmap,
+                                    mode,
+                                    grayscale_filter_strength,
+                                    slot->library );
+
       }
 
-#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+      /* Global values */
+      if ( brightness_value != 0 || contrast_value != 0 )
+        _ft_bitmap_bc ( bitmap,
+                        (float)brightness_value / 300.0,
+                        (float)contrast_value / 300.0);
 
+      FT_Outline_Done( slot->library, outline_orig );
     }
+    else if ( mode == FT_RENDER_MODE_LCD     &&
+              lcd_filter_func )
+          lcd_filter_func( bitmap, mode, lcd_weights );
+#else
+    if ( lcd_filter_func )
+      lcd_filter_func( bitmap, mode, lcd_weights );
+#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */
 
-  Exit:
-    if ( !error )
+#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+    /* render outline into bitmap */
+    error = render->raster_render( render->raster, &params );
+    if ( error )
+      goto Exit;
+
+    /* expand it horizontally */
+    if ( hmul )
     {
-      /* everything is fine; the glyph is now officially a bitmap */
-      slot->format = FT_GLYPH_FORMAT_BITMAP;
+      FT_Byte*  line = bitmap->buffer;
+      FT_UInt   hh;
+
+
+      for ( hh = height_org; hh > 0; hh--, line += pitch )
+      {
+        FT_UInt   xx;
+        FT_Byte*  end = line + width;
+
+
+        for ( xx = width_org; xx > 0; xx-- )
+        {
+          FT_UInt  pixel = line[xx-1];
+
+
+          end[-3] = (FT_Byte)pixel;
+          end[-2] = (FT_Byte)pixel;
+          end[-1] = (FT_Byte)pixel;
+          end    -= 3;
+        }
+      }
+    }
+
+    /* expand it vertically */
+    if ( vmul )
+    {
+      FT_Byte*  read  = bitmap->buffer + ( height - height_org ) * pitch;
+      FT_Byte*  write = bitmap->buffer;
+      FT_UInt   hh;
+
+
+      for ( hh = height_org; hh > 0; hh-- )
+      {
+        ft_memcpy( write, read, pitch );
+        write += pitch;
+
+        ft_memcpy( write, read, pitch );
+        write += pitch;
+
+        ft_memcpy( write, read, pitch );
+        write += pitch;
+        read  += pitch;
+      }
     }
-    else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+
+#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+    /*
+     * XXX: on 16bit system, we return an error for huge bitmap
+     * to prevent an overflow.
+     */
+    if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX )
+    {
+      error = FT_THROW( Invalid_Pixel_Size );
+      goto Exit;
+    }
+
+    slot->format      = FT_GLYPH_FORMAT_BITMAP;
+    slot->bitmap_left = (FT_Int)x_left;
+    slot->bitmap_top  = (FT_Int)y_top;
+
+    /* everything is fine; don't deallocate buffer */
+    have_buffer = FALSE;
+
+    error = FT_Err_Ok;
+
+  Exit:
+    if ( have_outline_shifted )
+      FT_Outline_Translate( outline, x_shift, y_shift );
+    if ( have_translated_origin )
+      FT_Outline_Translate( outline, -origin->x, -origin->y );
+    if ( have_buffer )
     {
       FT_FREE( bitmap->buffer );
       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
     }
 
-    if ( x_shift || y_shift )
-      FT_Outline_Translate( outline, -x_shift, -y_shift );
+    return error;
+  }
+
+
+
+  /* convert a slot's glyph image into a horizontal LCD bitmap */
+  static FT_Error
+  ft_smooth_render_lcd( FT_Renderer       render,
+                        FT_GlyphSlot      slot,
+                        FT_Render_Mode    mode,
+                        const FT_Vector*  origin )
+  {
+    FT_Error  error;
+
+    error = ft_smooth_render_generic( render, slot, mode, origin,
+                                      FT_RENDER_MODE_LCD );
+    if ( !error )
+      slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
 
     return error;
   }
 
 
+  /* convert a slot's glyph image into a vertical LCD bitmap */
+  static FT_Error
+  ft_smooth_render_lcd_v( FT_Renderer       render,
+                          FT_GlyphSlot      slot,
+                          FT_Render_Mode    mode,
+                          const FT_Vector*  origin )
+  {
+    FT_Error  error;
+
+    error = ft_smooth_render_generic( render, slot, mode, origin,
+                                      FT_RENDER_MODE_LCD_V );
+    if ( !error )
+      slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
+
+    return error;
+  }
+
+
+
+  /* convert a slot's glyph image into a bitmap */
+  static FT_Error
+  ft_smooth_render( FT_Renderer       render,
+                    FT_GlyphSlot      slot,
+                    FT_Render_Mode    mode,
+                    const FT_Vector*  origin )
+  {
+    switch (mode) {
+      case FT_RENDER_MODE_LIGHT:
+      case FT_RENDER_MODE_NORMAL:
+        return ft_smooth_render_generic( render, slot, mode, origin,
+                                     FT_RENDER_MODE_NORMAL );
+      case FT_RENDER_MODE_LCD:
+        return ft_smooth_render_lcd( render, slot, mode, origin);
+      case FT_RENDER_MODE_LCD_V:
+        return ft_smooth_render_lcd_v( render, slot, mode, origin);
+    }
+  }
+
+
   FT_DEFINE_RENDERER(
     ft_smooth_renderer_class,
 
